一、整體流程
做了A和B。
大膽猜想,直接寫碼……
二、具體題目
A. Windblume Ode
(1)讀題
①場上:從樣例解釋中發現,輸出時的順序無關緊要,換句話講,輸出1 2 3 ... 8 9與輸出6 9 1 2 3 ... 8都算正確。
題目要求集合大小盡量大,但不需要總值最大。同時,需要判斷合數或者素數。
那么,如果保證是合數的話,就可以直接輸出;如果是素數的話,可以想辦法減為合數。
②改進:可以大膽猜想算法。一般對於最簡單的一道題,都有着非常容易寫出的代碼,即不考察算法和碼力,轉而考慮數學猜想和證明能力。對於此題,大膽猜想可隨意刪除一個數字,如果保證刪除此數后新的和為合數,就貪心的輸出答案。
③證明:在和本身為合數的情況下,直接輸出答案。如果本身不是合數,那么和一定是質數,也一定是奇數。既然和是奇數,那么只要再減去一個奇數就可以變成偶數了,既然是偶數,那么也必然是合數。考慮到和為奇數,那么一定有起碼一個奇數,即充分性。
(2)做題
由於int sum=0;定義在了函數外,wa了兩次。
素數篩

#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; bool isGood[300000];//�Ƿ�Ϊ���� void init(){ for(int i=2;i<=20000;i++){ for(int j=2;j<=20000;j++){ if(i*j>20000)continue; else isGood[i*j]=1; } } } int a[200]; int main() { //cout<<Miller_Rabin(3)<<endl; init(); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); int sum=0; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; } //printf("isGood[%d]=%d\n",sum,isGood[sum]); if(isGood[sum]){//�����Ǻ��� printf("%d\n",n); for(int i=1;i<=n;i++){ printf("%d ",i); } printf("\n"); }else{//�����Ǻ��� //ȥ��һ������ʹ��ȥ�����sumΪ������Ȼ������� int removeIndex=0; for(int i=1;i<=n;i++){ if(isGood[sum-a[i]]){ removeIndex=i; //printf("removeIndex:%d\n",removeIndex); break; } } printf("%d\n",n-1); for(int i=1;i<=n;i++){ if(i!=removeIndex){ printf("%d ",i); } } printf("\n"); } } return 0; }
Miller-Rabin

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int prime[10]={2,3,5,7,11,13,17,19,23,29}; int Quick_Multiply(int a,int b,int c) { long long ans=0,res=a; while(b) { if(b&1) ans=(ans+res)%c; res=(res+res)%c; b>>=1; } return (int)ans; } int Quick_Power(int a,int b,int c) { int ans=1,res=a; while(b) { if(b&1) ans=Quick_Multiply(ans,res,c); res=Quick_Multiply(res,res,c); b>>=1; } return ans; } bool Miller_Rabin(int x) { int i,j,k; int s=0,t=x-1; if(x==2) return true; if(x<2||!(x&1)) return false; while(!(t&1)) { s++; t>>=1; } for(i=0;i<10&&prime[i]<x;++i) { int a=prime[i]; int b=Quick_Power(a,t,x); for(j=1;j<=s;++j) { k=Quick_Multiply(b,b,x); if(k==1&&b!=1&&b!=x-1) return false; b=k; } if(b!=1) return false; } return true; } int a[200]; int main() { int T; scanf("%d",&T); while(T--){ int sum=0; int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum+=a[i]; } if(!Miller_Rabin(sum)){//?????????? printf("%d\n",n); for(int i=1;i<=n;i++){ printf("%d ",i); } printf("\n"); }else{ //???????????????????sum??????????????? int removeIndex=0; for(int i=1;i<=n;i++){ if(!Miller_Rabin(sum-a[i])){ removeIndex=i; //printf("removeIndex:%d\n",removeIndex); break; } } printf("%d\n",n-1); for(int i=1;i<=n;i++){ if(i!=removeIndex){ printf("%d ",i); } } printf("\n"); } } return 0; }
B. Omkar and Heavenly Tree
(1)讀題
①場上:題意要求兩點之間的簡單路徑中不能有違法點,考慮重新建圖。注意到兩點之間如果有任何限制,那么連接這兩個點,就可以直接忽略掉這些限制。但是如果直接連接輸出答案的話,可能出現環或者其他構造答案,因此要換一種連點越過限制的方法。
②改進:div2的B題一般不會太難,難度主要在思維上。重新審視要求,發現對於樹的類型和形狀沒有確切的規定,輸出答案十分自由。那么聯想到"菊花圖"
③證明:菊花圖有着一個特性:任意兩點之間的中間點必然有且只有中心點和兩點上面的點。聯合a,b,c均獨特的特性,得到正解為構造一顆深度為2的菊花圖.
(2)做題

#include<cstdio> #include<iostream> using namespace std; bool baned[200000]; int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)baned[i]=0; for(int i=1;i<=m;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); baned[b]=1; } for(int i=1;i<=n;i++){ if(!baned[i]){//根 for(int j=1;j<=n;j++){ if(j!=i) printf("%d %d\n",i,j); } break; } } } return 0; }