题目链接:http://lightoj.com/volume_showproblem.php?problem=1021
#include<cstring> #include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int maxn = 1<<16; const int INF = 0x3f3f3f3f; long long dp[maxn][20]; //dp[i][j]表示数字集合为i(数位i上为1,代表第i个数取了),对K取余为j的数的各个数位上总的排列数。 int num[20]; int base,K; char s[20]; int main() { // freopen("E:\acm\input.txt","r",stdin); int T; cin>>T; for(int cas=1;cas<=T;cas++){ scanf("%d %d",&base,&K); scanf("%s",s); int len = strlen(s); for(int i=0;i<len;i++){ if(s[i]>='0' && s[i] <= '9') num[i] = s[i] - '0'; else num[i] = 10 + s[i] - 'A'; } memset(dp,0,sizeof(dp)); dp[0][0] = 1; //表示各位都没有数字,余数为0的个数有一个,即0. for(int i=0;i<(1<<len);i++) //枚举不同数字集合 for(int j=0;j<K;j++){ //枚举不同数字集合下的余数情况。 if(!dp[i][j]) continue; for(int k=0;k<len;k++){ //i在第k个数位已经有1,直接跳过。 if(i & (1<<k)) continue; dp[i|(1<<k)][(j*base+num[k])%K] += dp[i][j]; //j*base+num[k])%K 表示把第k个数加到dp[i][j]中排列数的末尾,新组成的数对K取余后得到余数。 //假设dp[i][j]中的任一个数为num, 则 余数就为(num*base + num[k])% K; 而 num%K == j。 所以利用取模运算就可以化简得到(j*base+num[k])%K } } printf("Case %d: %lld ",cas,dp[(1<<len)-1][0]); } } //参考别人的代码写的,非原著。