题意:给出一个数字num和m。问通过又一次排列num中的各位数字中有多少个数(mod m)=0,直接枚举全排列肯定不行,能够用状压dp来搞..
dp[S][k]表示选了num中的S且(mod m)=k的方案种数,初始条件dp[0][0]=1,转移方为dp[i|1<<j[(10*k+num[j])%m]+=dp[i}[k];,注意到是多重排列。所以还须要除去反复的。代码例如以下:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[1<<18][100],c[20];//dp[S][k]表示选了num中的S且(mod m)=k的方案种数
int main(int argc, char const *argv[])
{
char num[20];
int m;
while(cin>>num>>m) {
memset(dp,0,sizeof dp);
memset(c,0,sizeof c);
dp[0][0]=1;
ll div=1,sz=strlen(num),t=1<<sz;
for(int i=0;i<sz;i++) {
div*=(++c[num[i]-='0']);//可重排列最后要除的除数n1!*n2!*...nk!
}
for(int i=0;i<t;i++) {
for(int j=0;j<sz;j++)if(!(i&1<<j)) {//集合S中不含j才转移
if(num[j]||i){//至少一个不为0保证无前导0
for(int k=0;k<m;k++) {
dp[i|1<<j][(10*k+num[j])%m]+=dp[i][k];
}
}
}
}
cout<<dp[t-1][0]/div<<endl;
}
return 0;
}
版权声明:本文博主原创文章。博客,未经同意不得转载。