#include #include #include using namespace std; int visited[5][20][9009];// 访问情况 int dp[5][20][9009]; // M N num num即M-1位的数字 int num_2[7]= {2,3,5,7,11,13,17}; int num_3[9]= {2,3,5,7,11,13,17,19,23}; int num_4[11]= {2,3,5,7,11,13,17,19,23,29,31}; //存储素数 int N,M; int delete_head(int num,int m) //去掉当前数字的首个数字 { int ans; if (m==2) return 0; if (m==3) ans=num-num/10*10; if (m==4) ans=num-num/100*100; return ans; } int divide_num(int num) { int ans=0; while (num>0) { ans+=num; num=num/10; } return ans; } int select_num(int k,int sum,int m) { if (m==2) { for (int i=0; i<7; i++) if (k+divide_num(sum)==num_2[i]) return 1; return 0; } if (m==3) { for (int i=0; i<9; i++) if (k+divide_num(sum)==num_3[i]) { return 1; } return 0; } if (m==4) { for (int i=0; i<11; i++) if (k+divide_num(sum)==num_4[i]) return 1; return 0; } } void work(int m,int n,int num) { if (n==0) // n=0直接处理 { visited[m][n][num]=1; dp[m][n][num]=1; } else { if (!visited[m][n][num]) { visited[m][n][num]=1; for (int k=0; k<=9; k++) { if (select_num(k,num,m)) { int next=delete_head(num,m)*10+k; //next是num的下个状态(去头加尾) if (!visited[m][n-1][next]) { work(m,n-1,next); } dp[m][n][num]+=dp[m][n-1][next]; } } } } } int main() { memset(visited,0,sizeof(visited)); memset(dp,0,sizeof(dp)); scanf("%d %d",&N,&M); if (M==1) { int ans=1; while (N>0) { ans*=4; N--; } printf("%d ",ans); } if (M==2) { int ans=0; for (int i=0; i<=9; i++) { int num=i; work(M,N-1,num); ans+=dp[M][N-1][num]; } printf("%d ",ans); } if (M==3) { int ans=0; for (int i=0; i<=9; i++) for (int k=0; k<=9; k++) { int num=i*10+k; work(M,N-2,num); ans+=dp[M][N-2][num]; } printf("%d ",ans); } if (M==4) { int ans=0; for (int i=0; i<=9; i++) for (int k=0; k<=9; k++) for (int x=0; x<=9; x++) { int num=i*100+k*10+x; work(M,N-3,num); ans+=dp[M][N-3][num]; } printf("%d ",ans); } return 0; }
小明的密码由N(1<=N<=12)个数字构成,每个数字都可以是0至9中任意一个数字,但小明的密码还有 一个特点就是密码中连续的M(1<=M<=4)个数字的和是质数,现给定M和N,求满足条件的密码共有多少 个? 输入格式 第1行是T,case数量,此后T行,每行两个数,N和M 输出格式 每个case输出一个满足条件的密码总数
输入样例
2
1 1
2 1
输出样例
4
16
作者 admin
第一次做多维DP,虽然才做到第三个维度,感觉已经够狠的题目还可以出的更复杂,比如M更大的时候我还没想过怎么操作,暂时做到三维DP,主要是做第三维的时候遇到困难,第一次做的时候把前M-1位的数字和求出来做参数,没想到维度混淆了,还是只能用M-1做真整数,这样如果M稍微大一点,我可能都要做高精度了,而且内存也不宽裕,继续努力想其他解法吧
1 #include <cstdlib> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 int visited[5][20][9009];// 访问情况 6 int dp[5][20][9009]; // M N num num即M-1位的数字 7 int num_2[7]= {2,3,5,7,11,13,17}; 8 int num_3[9]= {2,3,5,7,11,13,17,19,23}; 9 int num_4[11]= {2,3,5,7,11,13,17,19,23,29,31}; //存储素数 10 int N,M; 11 int delete_head(int num,int m) //去掉当前数字的首个数字 12 { 13 int ans; 14 if (m==2) return 0; 15 if (m==3) ans=num-num/10*10; 16 if (m==4) ans=num-num/100*100; 17 return ans; 18 } 19 int divide_num(int num) 20 { 21 int ans=0; 22 while (num>0) 23 { 24 ans+=num; 25 num=num/10; 26 } 27 return ans; 28 } 29 int select_num(int k,int sum,int m) 30 { 31 if (m==2) 32 { 33 for (int i=0; i<7; i++) if (k+divide_num(sum)==num_2[i]) return 1; 34 return 0; 35 } 36 if (m==3) 37 { 38 for (int i=0; i<9; i++) 39 if (k+divide_num(sum)==num_3[i]) 40 { 41 return 1; 42 } 43 return 0; 44 } 45 if (m==4) 46 { 47 for (int i=0; i<11; i++) if (k+divide_num(sum)==num_4[i]) return 1; 48 return 0; 49 } 50 } 51 void work(int m,int n,int num) 52 { 53 if (n==0) // n=0直接处理 54 { 55 visited[m][n][num]=1; 56 dp[m][n][num]=1; 57 } 58 else 59 { 60 if (!visited[m][n][num]) 61 { 62 visited[m][n][num]=1; 63 for (int k=0; k<=9; k++) 64 { 65 if (select_num(k,num,m)) 66 { 67 int next=delete_head(num,m)*10+k; //next是num的下个状态(去头加尾) 68 if (!visited[m][n-1][next]) 69 { 70 work(m,n-1,next); 71 } 72 dp[m][n][num]+=dp[m][n-1][next]; 73 } 74 } 75 } 76 } 77 } 78 int main() 79 { 80 memset(visited,0,sizeof(visited)); 81 memset(dp,0,sizeof(dp)); 82 scanf("%d %d",&N,&M); 83 if (M==1) 84 { 85 int ans=1; 86 while (N>0) 87 { 88 ans*=4; 89 N--; 90 } 91 printf("%d ",ans); 92 } 93 if (M==2) 94 { 95 int ans=0; 96 for (int i=0; i<=9; i++) 97 { 98 int num=i; 99 work(M,N-1,num); 100 ans+=dp[M][N-1][num]; 101 } 102 printf("%d ",ans); 103 } 104 if (M==3) 105 { 106 int ans=0; 107 for (int i=0; i<=9; i++) 108 for (int k=0; k<=9; k++) 109 { 110 int num=i*10+k; 111 work(M,N-2,num); 112 ans+=dp[M][N-2][num]; 113 } 114 printf("%d ",ans); 115 } 116 if (M==4) 117 { 118 int ans=0; 119 for (int i=0; i<=9; i++) 120 for (int k=0; k<=9; k++) 121 for (int x=0; x<=9; x++) 122 { 123 int num=i*100+k*10+x; 124 work(M,N-3,num); 125 ans+=dp[M][N-3][num]; 126 } 127 printf("%d ",ans); 128 } 129 return 0; 130 }