【qboi冲刺NOIP2017复赛试题4】 全套题目+题解+程序
作为一个好人(验题人),我给大家奉上下这套题的题解,并且预祝大家这套题能够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 }
是不是很简单啊??