题意:给一个数字串,可以调换数字,问有多少种组合可以让组成的数能被11整除。
思路:窝们观察到1%11=1, 10%11=10,100%11=1,1000%11=10,以此类推。。窝们将一偶一奇看作一对,这一对组成对11的余数
×100对11的余数(也就是1),所以实质还是这一对对11的余数,那么奇偶数位的和就可以了。我们可以设奇数位的和为x,偶数位的
和为y,则(x+10y)%11的值为0就可以了--> (x-y+11y)%11=0 --> (x-y)%11=0。所以设dp[i][j][k]表示处理完0到i-1,已在奇数位放了j个
数字,(奇数位数字和-偶数位数字和)%11=k的种数,详见代码:
/*********************************************************
file name: LA6529.cpp
author : kereo
create time: 2015年02月04日 星期三 20时39分19秒
*********************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int N=15;
const int MAXN=100+10;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
char str[MAXN];
int num[N];
ll C[MAXN][MAXN];
ll dp[N][MAXN][N];//dp[i][j][k]表示处理完0到i-1,已在奇数位放了j个数字,(奇数位数字和-偶数位数字和)%11=k的种数
void init(){
for(int i=0;i<MAXN;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
ll solve(int len){
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
int sum=0,n=(len+1)>>1;
for(int i=0;i<10;i++){ //处理的数位
for(int j=0;j<=sum && j<=n;j++){ //已放在奇数位的个数
for(int k=0;k<=num[i] && k<=n-j;k++){ //这次在奇数位放的个数
int x=((2*k-num[i])*i)%11;
if(x<0)
x+=11;
for(int st=0;st<=10;st++){
dp[i+1][j+k][(st+x)%11]=((((dp[i][j][st]*C[n-j][k])%mod)*C[len-sum-(n-j)][num[i]-k])%mod+dp[i+1][j+k][(st+x)%11])%mod;
}
}
}
sum+=num[i];
}
return dp[10][n][0];
}
int main(){
init();
while(~scanf("%s",str)){
memset(num,0,sizeof(num));
int n=strlen(str);
for(int i=0;i<n;i++)
num[str[i]-'0']++;
ll ans1=solve(n),ans2=0;
if(num[0]){ //剔除前导零的情况
num[0]--;
ans2=solve(n-1);
}
printf("%lld\n",((ans1-ans2)%mod+mod)%mod);
}
return 0;
}