[BZOJ 1072] 排列perm
Link:
Solution:
一道直接next_permutation纯暴力就能过的题?
难道2007年时大家都不知道next_permutation这个函数吗
还是用复杂度更优的状压DP吧
设$dp[i][j]$为状态为$i$且对$d$余$j$的个数,
注意$dp[(1<<len)-1][0]$最后除去$\prod_{i=0}^9 cnt[i]!$,排除重复项
现在对状压DP状态的选取有了些感悟,
一般来说第一项表示状态,而第二项表示的一般都是于答案相关且包含答案情况的
(EX:求整除,表示当前对$d$的余数)
Code:
#include <bits/stdc++.h> using namespace std; int T,d,len,cnt[15],dupli[15],dp[1200][1010]; char s[15]; int main() { scanf("%d",&T); while(T--) { scanf("%s %d",s,&d);len=strlen(s); for(int i=0;i<15;i++) dupli[i]=1; memset(cnt,0,sizeof(cnt));memset(dp,0,sizeof(dp)); for(int i=0;i<len;i++) cnt[s[i]-'0']++,dupli[s[i]-'0']*=cnt[s[i]-'0']; dp[0][0]=1; for(int i=0;i<(1<<len);i++) for(int j=0;j<d;j++) if(dp[i][j]) for(int k=0;k<len;k++) if(!(i&(1<<k))) dp[i|(1<<k)][(j*10+(s[k]-'0'))%d]+=dp[i][j]; for(int i=0;i<=9;i++) dp[(1<<len)-1][0]/=dupli[i]; printf("%d\n",dp[(1<<len)-1][0]); } return 0; }