【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 }

 

是不是很简单啊??

 

posted @ 2017-10-28 11:56  AlphaInf  阅读(2902)  评论(4编辑  收藏  举报