先贴代码 USER: Gao Bicheng [volz.kz1] TASK: prime3 LANG: C++ Compiling... Compile: OK Executing...
Test 1: TEST OK [0.011 secs, 8032 KB] Test 2: TEST OK [0.011 secs, 8032 KB] Test 3: TEST OK [0.032 secs, 8032 KB] Test 4: TEST OK [0.032 secs, 8032 KB] Test 5: TEST OK [0.043 secs, 8032 KB] Test 6: TEST OK [0.022 secs, 8032 KB] Test 7: TEST OK [0.032 secs, 8032 KB] Test 8: TEST OK [0.043 secs, 8032 KB] Test 9: TEST OK [0.065 secs, 8032 KB] Test 10: TEST OK [0.054 secs, 8032 KB] All tests OK.额,提交了6次,把continue的地方用成了return,这。。我也无奈了/* ID: volz.kz.g PROB: prime3 LANG: C++ */ #include <iostream> #include <fstream> #include <cstring> using namespace std; ifstream fin("prime3.in"); ofstream fout("prime3.out"); int sum,tot;//sum表示每一行每一列以及对角线的数字之和,tot保存大于10000的素数个数 int seq[25];//保存25位长度的序列 int prime[20000];//保存大于10000的第i个素数 bool check[100000];//判断编号为i的数字是否为素数 int put_prime_first[46][10][200]; int put_prime_third[46][10][200]; int put_prime_second_fourth[46][10][10][20]; int put_prime_first_third_fifth[46][10][10][10][10]; int put_prime_second_third_fourth[46][10][10][10][10]; int ans[100][25]; int ans_num; inline void euler(){ memset(check,true,sizeof(check)); for (int i=2;i<100000;i++){ if (check[i]) prime[tot++]=i; for (int j=0;j<tot;j++){ if (i*prime[j]>=100000) break; check[i*prime[j]]=false; if (i%prime[j]==0) break; } } } inline void get_put_prime(){ for (int i=0;i<tot;i++) if (prime[i]>=10000){ int j=prime[i],k=0,k1=prime[i]/10000,k2=(prime[i]/1000)%10,k3=(prime[i]/100)%10,k4=(prime[i]/10)%10,k5=(prime[i])%10; while (j>0){ k+=j % 10; j/=10; } put_prime_first[k][k1][0]++; put_prime_first[k][k1][put_prime_first[k][k1][0]]=prime[i]; put_prime_third[k][k3][0]++; put_prime_third[k][k3][put_prime_third[k][k3][0]]=prime[i]; put_prime_second_fourth[k][k2][k4][0]++; put_prime_second_fourth[k][k2][k4][put_prime_second_fourth[k][k2][k4][0]]=prime[i]; put_prime_first_third_fifth[k][k1][k3][k5][0]++; put_prime_first_third_fifth[k][k1][k3][k5][put_prime_first_third_fifth[k][k1][k3][k5][0]]=prime[i]; put_prime_second_third_fourth[k][k2][k3][k4][0]++; put_prime_second_third_fourth[k][k2][k3][k4][put_prime_second_third_fourth[k][k2][k3][k4][0]]=prime[i]; } } inline bool check_func(int x,int y){ for (int i=0;i<25;i++){ if (ans[x][i]<ans[y][i]) return false; if (ans[x][i]>ans[y][i]) return true; } return false; } inline void print(){ for (int j=1;j<=ans_num;j++){ for (int i=0;i<25;i++){ fout << ans[j][i]; if ((i+1)%5==0) fout << endl; } if (j!=ans_num) fout << endl; } } inline void find_seq(int step){ switch (step){ int k1,k2,k3,k4,k5,num; case 0: k1=seq[0]; for (int i=1;i<=put_prime_first[sum][k1][0];i++){ num = put_prime_first[sum][k1][i]; seq[24]=num%10;num/=10; seq[18]=num%10;num/=10; seq[12]=num%10;num/=10; seq[6]=num%10;num/=10; find_seq(step+1); } break; case 1: k3=seq[12]; for (int i=1;i<=put_prime_third[sum][k3][0];i++){ num = put_prime_third[sum][k3][i]; seq[4]=num%10;num/=10;if (seq[4]==0) continue; seq[8]=num%10;num/=10; num/=10; seq[16]=num%10;num/=10; seq[20]=num%10;if (seq[20]==0) continue; find_seq(step+1); } break; case 2: k2=seq[6];k4=seq[8]; for (int i=1;i<=put_prime_second_fourth[sum][k2][k4][0];i++){ num = put_prime_second_fourth[sum][k2][k4][i]; seq[9]=num%10;num/=10; num/=10; seq[7]=num%10;num/=10; num/=10; seq[5]=num%10;if (seq[5]==0) continue; find_seq(step+1); } break; case 3: k2=seq[16];k4=seq[18]; for (int i=1;i<=put_prime_second_fourth[sum][k2][k4][0];i++){ num = put_prime_second_fourth[sum][k2][k4][i]; seq[19]=num%10;num/=10; num/=10; seq[17]=num%10;num/=10; num/=10; seq[15]=num%10;if (seq[15]==0) continue; find_seq(step+1); } break; case 4: seq[10]=sum-seq[0]-seq[5]-seq[15]-seq[20];if (seq[10]<=0 || seq[10]>=10) return; num=seq[0]*10000+seq[5]*1000+seq[10]*100+seq[15]*10+seq[20];if (!check[num]) return; seq[14]=sum-seq[4]-seq[9]-seq[19]-seq[24];if (seq[14]<0 || seq[14]>=10) return; num=seq[4]*10000+seq[9]*1000+seq[14]*100+seq[19]*10+seq[24];if (!check[num]) return; find_seq(step+1); break; case 5: k2=seq[7];k3=seq[12];k4=seq[17]; for (int i=1;i<=put_prime_second_third_fourth[sum][k2][k3][k4][0];i++){ num = put_prime_second_third_fourth[sum][k2][k3][k4][i]; seq[22]=num%10; num/=10000; seq[2]=num%10; find_seq(step+1); } break; case 6: k1=seq[0];k3=seq[2];k5=seq[4]; for (int i=1;i<=put_prime_first_third_fifth[sum][k1][k3][k5][0];i++){ num = put_prime_first_third_fifth[sum][k1][k3][k5][i]; num/=10; seq[3]=num%10;num/=10;if (seq[3]==0) continue; num/=10; seq[1]=num%10;num/=10;if (seq[1]==0) continue; find_seq(step+1); } break; case 7: k1=seq[20];k3=seq[22];k5=seq[24]; for (int i=1;i<=put_prime_first_third_fifth[sum][k1][k3][k5][0];i++){ num = put_prime_first_third_fifth[sum][k1][k3][k5][i]; num/=10; seq[23]=num%10;num/=10; num/=10; seq[21]=num%10;num/=10; find_seq(step+1); } break; case 8: seq[11]=sum-seq[1]-seq[6]-seq[16]-seq[21];if (seq[11]<0 || seq[11]>=10) return; num=seq[1]*10000+seq[6]*1000+seq[11]*100+seq[16]*10+seq[21];if (!check[num]) return; seq[13]=sum-seq[3]-seq[8]-seq[18]-seq[23];if (seq[13]<0 || seq[13]>=10) return; num=seq[3]*10000+seq[8]*1000+seq[13]*100+seq[18]*10+seq[23];if (!check[num]) return; num=seq[10]*10000+seq[11]*1000+seq[12]*100+seq[13]*10+seq[14];if (!check[num]) return; ans_num++; for (int i=0;i<25;i++) ans[ans_num][i]=seq[i]; break; } } int main(){ fin >> sum >> seq[0]; euler();//利用欧拉筛法寻找素数 get_put_prime();//得到每位数字之和为i,开头数字为j,这样的素数的第k个的素数表 find_seq(0); for (int i=1;i<ans_num;i++) for (int j=i+1;j<=ans_num;j++) if (check_func(i,j)){ int tmp; for (int k=0;k<25;k++){ tmp=ans[i][k]; ans[i][k]=ans[j][k]; ans[j][k]=tmp; } } print(); return 0; }
不过速度小快。
这道题目是典型的搜索优化题目,接下来就循序渐进的讲一下算法,
题目大意:在五行五列矩阵25个格子内,填入0-9,使每一行、每一列、对角线都是素数。并且该5位素数第一位不能为0,且每个素数的各位之和为给定的数sum,题目还
告诉了我们第一行第一列的那个数必须为x
算法1:
枚举25个格子内的数,然后进行素数判断,这样至少需要10^25次运算,超时明显
算法2:
假设我们已经枚举了前四行,那么对于最后一行上某一列的数,可以由sum-这一列前四行所有的数之和得到,因此我们的枚举次数降到了10^20
算法3:
算法2也是不行滴,从题目中我们可以知道,相当于每行每列都要是一个5位素数,那么我们可不可以尝试填入5个5位素数呢?
可以的。由于5位素数有8392个,因此现在的时间复杂度为8392^5=4.1*10^19
算法4:
我们可以用算法2的思想来优化算法3,时间复杂度降到了4.96*10^15次
目测我们已经降低了10^9次,优化的力量真是强大
算法5:
我们已经知道了利用枚举素数的方法,那么能不能再做一些提高呢
这时候,需要回顾一下题目,它说已经规定了第一行第一列的那个数了,想一下,
可以发现,这时候我们只需要枚举第一位已知的素数即可,这样的素数最多为106个
我们先得到第一行,然后得到第一列,接着从第一行得到的枚举每一列,
那么时间复杂度差不多为10^12
算法6:
算法5提供了我们一种思路,如果已知某一行或者某一列上的几个数,
那么我们只需要枚举已知这几位的素数即可
可以知道,已知2个位置上的数的5为素数最多11个,已知3个位置上的数的素数最多3个,通过不同的扩展方式
我们可以扩展出8.1*10^8时间复杂度的算法,也就是我的代码的算法,
接下来靠大家仔细研究吧。
usaco4.3.2
最新推荐文章于 2022-12-21 20:17:26 发布