标签:too names 考试 toolbar include bsp set 多次 int
注意一个细节:因为double的精度问题,输出0是可能会输出-0。
要特判一下。
考试时有多余时间一定要写暴力对拍啊,(可恶的万能样例竟然还过了)
我写了一个差分约束(用的裸的spfa),过了70分。但之后把spfa用双端队列deque或者优先队列优化以后,就快得飞起来,比正解(线段树+dp,这个差分约束也算正解了吧)还快。
dp[s][j]:表示s这个集合中的数构成的对d取模后等于j的数有多少个。
然后有一个小结论:
若 j=A%d,令 x=(A*10+B)%d,则 (j*10+B)%d==x
这个也很显然:
令 A=k*d+j,
则 x=((k*d+j)*10+B)%d
=(k*d*10+j*10+B)%d
=(j*10+B)%d
所以转移如下:
dp[s|(1<<k)][(j*10+s[k]-‘0‘)%d]+=dp[s][j];
最后处理一下出现多次的数字。因为不考虑相同数字的顺序,所以除以其出现次数的阶乘。
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char s[15]; int dp[1<<10][1005],c[15],fac[15]; int T,d,n; int idx(char ch){ return ch-‘0‘; } int main(){ scanf("%d",&T); fac[0]=1; for(int i=1;i<=10;i++) fac[i]=fac[i-1]*i; while(T--){ scanf("%s",s); scanf("%d",&d); memset(dp,0,sizeof(dp)); dp[0][0]=1; n=strlen(s); for(int i=0;i<(1<<n);i++) for(int j=0;j<d;j++){ if(!dp[i][j]) continue; for(int k=0;k<n;k++){ if(i&(1<<k)) continue; dp[i|(1<<k)][(j*10+idx(s[k]))%d]+=dp[i][j]; } } memset(c,0,sizeof(c)); for(int i=0;i<n;i++) c[idx(s[i])]++; for(int i=0;i<10;i++) dp[(1<<n)-1][0]/=fac[c[i]]; printf("%d\n",dp[(1<<n)-1][0]); } return 0; }
标签:too names 考试 toolbar include bsp set 多次 int
原文地址:http://www.cnblogs.com/zj75211/p/7732577.html