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 }
View Code
原文地址:https://www.cnblogs.com/SolarWings/p/3452690.html