codeforces#235_div2_D Roman and Numbers ,dp
题目地址:cf#235_div2_D
题目大意:给你一个整数(相当于给你一个集合) 现在问你,这些整数的全排列(不能有前导零)当中,有多少被m整除
先直接暴力 18的阶乘 显然是会超时的。
可以过到第12组数据
#include<iostream> #include<algorithm> using namespace std; long long n,m; int pp[18]; int digit; bool divided() { long long ans=0; for(int i=0;i<digit;i++) { ans=ans*10+pp[i]; } if(ans%m==0) return 1; else return 0; } int main() { cin>>n>>m; long long nn=n; int index=0; int p[18]; while(nn>0) { p[index++]=nn%10; nn/=10; } digit=index; for(int i=0;i<index;i++) { pp[i]=p[index-1-i]; } sort(pp,pp+digit); long long cnt=0; do { if(divided()&&pp[0]!=0) cnt++; } while (next_permutation(pp,pp+digit)); cout<<cnt<<endl; }
然后就是dp的写法,参照了yzc 的思路
实际上是枚举的最后一位的数码可能是什么,枚举完以后,拓扑序是集合元素的数量关系。
如果i==0 那么不能有前导零,所以数码不能为0
神奇只处在于 这样的贡献方式是补充不漏的。 具体原因还没有想清楚。
代码:
#include<iostream> #include<string> #include<cstring> using namespace std; typedef long long inta; inta dp[1<<18][101]; int b[20]; int p[20]; int m; int main() { string str; cin>>str>>m; int n=str.length(); for(int i=0;i<n;i++) b[i]=str[i]-48; memset(dp, 0, sizeof(dp)); dp[0][0]=1; for(int i=0;i<=(1<<n)-1;i++) { memset(p,-1 ,sizeof(p)); for(int j=0;j<n;j++) if(!(i&(1<<j))) p[b[j]]=j; for(int j=0;j<m;j++) { if(i) { for(int k=0;k<10;k++) if(p[k]>=0) dp[i|(1<<p[k])][(10*j+k)%m]+=dp[i][j]; } else { for(int k=1;k<10;k++) if(p[k]>=0) dp[i|(1<<p[k])][(10*j+k)%m]+=dp[i][j]; } } } cout<<dp[(1<<n)-1][0]<<endl; }
posted on 2014-03-16 23:47 814jingqi的ACM 阅读(178) 评论(0) 编辑 收藏 举报