Codeforces Round #235 (Div. 2) D. Roman and Numbers(如压力dp)
题意:给出一个数字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; }
版权声明:本文博主原创文章。博客,未经同意不得转载。