作為一個好人(驗題人),我給大家奉上下這套題的題解,並且預祝大家這套題能夠AK:
T1題面:Alice現在有n根木棍,他們長度為1,2,3....n,Bob想把某一些木棍去掉,使得Alice剩下的木棍任意3根不能構成三角形。Bob想知道至少他需要去掉多少根。
題解:不難發現,這一題所求為在[1,n]中有多少個數不是斐波那契數,因為n的范圍很小,直接枚舉即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define L long long 5 using namespace std; 6 L n,a=1,b=2,c; 7 8 int main(){ 9 freopen("a.in","r",stdin); 10 freopen("a.out","w",stdout); 11 cin>>n; 12 if(n<=3) {printf("0\n"); return 0;} 13 int i; 14 for(i=2;a+b<=n;i++){ 15 c=a+b; 16 a=b; b=c; 17 } 18 cout<<n-i<<endl; 19 }
第二題題面:給你n堆石子,每堆石子有ai個石子,對於每一次操作,可以將某堆的一個石子移動到另外一堆。游戲終止的條件是:存在一個x(x>1),使得任意一堆石子滿足:ai%x==0。(1<=i<=n)請求出游戲終止的最小操作數。
我們不難發現,x必為sum的因子,枚舉所有的因子d,對於該因子d,將a數組中每一個數取模並排序,最后貪心地掃一遍即可。
時間復雜度為$O(n*d(sum^{0.5}))$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define M 110000 6 #define L long long 7 using namespace std; 8 int a[M]={0},b[M]={0},dd[M]={0},n,dn; 9 L ans=0,minn=1e18; 10 11 void sort(int x){ 12 for(int i=1;i<=n;i++) dd[b[i]]++; 13 int cnt=0; 14 for(int i=0;i<x;i++){ 15 while(dd[i]) b[++cnt]=i,dd[i]--; 16 } 17 } 18 19 int main(){ 20 cin>>n; 21 for(int i=1;i<=n;i++) scanf("%d",a+i),ans+=a[i]; 22 for(int d=2;d<=100000;d++) if(ans%d==0){ 23 L sum=0,cnt=0; 24 for(int i=1;i<=n;i++) b[i]=a[i]%d; 25 sort(d); 26 //sort(b+1,b+n+1); 27 for(int i=1,j=n;i<j;i++){ 28 while(b[i]){ 29 int delta=min(b[i],d-b[j]); 30 cnt+=delta; 31 b[j]+=delta; 32 b[i]-=delta; 33 if(b[j]==d) j--;//!!! 34 } 35 } 36 minn=min(minn,cnt); 37 } 38 cout<<minn<<endl; 39 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define M 110000 6 #define L long long 7 using namespace std; 8 int a[M]={0},b[M]={0},dd[M]={0},n,dn; 9 L ans=0,minn=1e18; 10 11 void sort(int x){ 12 for(int i=1;i<=n;i++) dd[b[i]]++; 13 int cnt=0; 14 for(int i=0;i<x;i++){ 15 while(dd[i]) b[++cnt]=i,dd[i]--; 16 } 17 } 18 19 int main(){ 20 cin>>n; 21 for(int i=1;i<=n;i++) scanf("%d",a+i),ans+=a[i]; 22 for(int d=2;d<=100000;d++) if(ans%d==0){ 23 L sum=0,cnt=0; 24 for(int i=1;i<=n;i++) b[i]=a[i]%d; 25 sort(d); 26 //sort(b+1,b+n+1); 27 for(int i=1,j=n;i<j;i++){ 28 while(b[i]){ 29 int delta=min(b[i],d-b[j]); 30 cnt+=delta; 31 b[j]+=delta; 32 b[i]-=delta; 33 if(b[j]==d) j--;//!!! 34 } 35 } 36 minn=min(minn,cnt); 37 } 38 cout<<minn<<endl; 39 }
第三題題解:簡單亂搞題,直接暴力枚舉即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define M 1100 5 using namespace std; 6 int n,m,d; 7 struct pt{ 8 int x,y; pt(){x=y=0;} 9 pt(int xx,int yy) {x=xx; y=yy;} 10 }a[M]; 11 int f[M]={0},ok[M]={0}; 12 int get(int x){ 13 if(f[x]!=x) return f[x]=get(f[x]); 14 return x; 15 } 16 int pf(int x){return x*x;} 17 bool cmp(int x,int y){ 18 return pf(a[x].x-a[y].x)+pf(a[x].y-a[y].y)<=d*d; 19 } 20 struct edge{int u,next;}e[M*M]={0}; int head[M]={0},use=0; 21 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x]; head[x]=use;} 22 int main(){ 23 scanf("%d%d%d",&n,&m,&d); 24 for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); 25 for(int i=1;i<=n;i++){ 26 for(int j=1;j<=n;j++) if(i!=j) 27 if(cmp(i,j)) 28 add(i,j); 29 } 30 for(int i=1;i<=n;i++) f[i]=i; 31 while(m--){ 32 char c[10]; int x,y; 33 scanf("%s%d",&c,&x); 34 if(c[0]=='O'){ 35 ok[x]=1; 36 for(int i=head[x];i;i=e[i].next) if(ok[e[i].u]){ 37 int xx=get(x),yy=get(e[i].u); 38 if(xx==yy) continue; 39 f[xx]=yy; 40 } 41 } else{ 42 scanf("%d",&y); 43 x=get(x); y=get(y); 44 if(x==y) printf("YES\n"); 45 else printf("NO\n"); 46 } 47 } 48 }
第四題題解:我們對所所有的買賣方案按 Q-P 的大小 ,從小到大排序,然后直接跑01背包即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct node 4 { 5 int p,q,v; 6 node(){} 7 bool operator < (const node &a) const 8 { 9 return q-p < a.q - a.p; 10 } 11 void read() {scanf("%d%d%d",&p,&q,&v);} 12 }a[1000]; 13 int f[100050]; 14 int main() 15 { 16 int n,m; 17 while (scanf("%d%d",&n,&m)!=EOF) 18 { 19 memset(f,0,sizeof(f)); 20 for (int i=1; i<=n; i++) a[i].read(); 21 sort(a+1,a+1+n); 22 for (int i=1; i<=n; i++) 23 for (int j=m; j>=a[i].q; j--) 24 f[j] = max(f[j], f[j-a[i].p]+a[i].v); 25 printf("%d\n",f[m]); 26 } 27 }
是不是很簡單啊??