loj 1021(状压dp+记忆化搜索)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=25887
题目大意:给定的一个某进制下的排列,问它的全排列有多少个能够整除给定的十进制下的数字k。
思路:记忆化搜索,dp[state][r]表示在某状态下被k除余数为r有多少个。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define FILL(a,b) memset(a,b,sizeof(a)) 8 typedef long long ll; 9 10 int base,k,len,num[17]; 11 ll dp[1<<17][21]; 12 char str[21]; 13 14 ll dfs(int state,int mod) 15 { 16 if(state==(1<<len)-1){ 17 return mod==0; 18 } 19 if(dp[state][mod]!=-1)return dp[state][mod]; 20 ll ans=0; 21 for(int i=len-1;i>=0;i--){ 22 if(!(state&(1<<i))){ 23 ans+=dfs(state|(1<<i),(mod*base+num[i])%k); 24 } 25 } 26 return dp[state][mod]=ans; 27 } 28 29 int main() 30 { 31 int _case,t=1; 32 scanf("%d",&_case); 33 while(_case--){ 34 scanf("%d%d",&base,&k); 35 scanf("%s",str); 36 len=strlen(str); 37 for(int i=0;i<len;i++){ 38 if(str[i]>='0'&&str[i]<='9')num[i]=str[i]-'0'; 39 else num[i]=str[i]-'A'+10; 40 } 41 FILL(dp,-1); 42 printf("Case %d: %lld\n",t++,dfs(0,0)); 43 } 44 return 0; 45 }