#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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",ans); 128 } 129 return 0; 130 }