UVALive 6529
题意:
给你一个串数字,可以按任意顺序排列,求有几种排列可以使他们组成的数字可以被11整除。
思路:
和前几天那个被9整除的思想类似,1%11=1,10%11=10,100%11=1,1000%11=10.....容易观察出,设奇数位的和为x,偶数位的和为y,则(x+10y)%11的值为0就可以了--> (x-y+11y)%11=0 --> (x-y)%11=0。
然后就可以dp做了dp[i][j][k]分别表示,当前在放数字i-1,之前已经放了j个数字,现在(x-y)%11的值为k。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define MOD 1000000007 6 typedef long long LL; 7 LL C[110][110],num[15]; 8 LL dp[11][101][11]; 9 10 char ch[110]; 11 void init(){ 12 C[0][0]=C[1][0]=C[1][1]=1; 13 for(int i=2;i<=100;i++){ 14 for(int j=0;j<=i;j++){ 15 if(j==0) C[i][j] = 1; 16 else C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD; 17 } 18 } 19 } 20 21 LL cal(int len){ 22 memset(dp,0,sizeof(dp)); 23 dp[0][0][0]=1; 24 int sum = 0; int need = (len+1)>>1; 25 for(int i=1;i<=10;i++){ 26 for(int j=0;j<=sum && j<=need;j++){ 27 for(int k=0;k<=num[i-1] && (j+k)<=need;k++){ 28 int change = (2*k-num[i-1])*(i-1)%11; 29 if(change<0) change+=11; 30 for(int l=0;l<11;l++){ 31 int next = (change + l)%11; 32 dp[i][j+k][next] = (dp[i][j+k][next] + dp[i-1][j][l] * C[need-j][k] %MOD* C[len-need-sum+j][num[i-1]-k] %MOD)%MOD; 33 } 34 } 35 } 36 sum+=num[i-1]; 37 } 38 return dp[10][need][0]; 39 } 40 41 void solve(){ 42 memset(num,0,sizeof(num)); 43 for(int i=0;ch[i];i++){ 44 num[ch[i]-'0']++; 45 } 46 int len=strlen(ch); 47 LL ans = cal(len); 48 if(num[0]){ 49 num[0]--; 50 LL ans2 = cal(len-1); 51 ans=((ans-ans2)%MOD+MOD)%MOD; 52 } 53 cout<<ans<<endl; 54 } 55 56 int main(){ 57 init(); 58 while(scanf("%s",ch)!=EOF){ 59 solve(); 60 } 61 return 0; 62 }