2017校赛题解

来源:互联网 发布:有没有画画软件 编辑:程序博客网 时间:2024/05/21 04:24

又是一年一度的校赛,三个人从出题到准备环境花了好几天的时间。虽然也是蛮累的,期间出了一些小差错,但总的来说还是蛮成功的【感觉比去年好一些,逃。。。】

 

一共出了7题,但是考虑到比赛时间比较紧张就砍掉了两题【反正没砍我的题,,】,给大家ak带来了很大的便利。这里我把题解和标程公布出来,欢迎大家给出更优的代码。

 

 

对了,关于@teddywang同学在题面上黑我的情况表示强烈谴责,将在他不注意的时候实施精确打击,,,


 

teddy打羽毛球

 

问题描述:

teddy和小zc去体育馆打了几局羽毛球,每局有数个回合,获胜的一方得到1分而失败方不会得分。一旦玩家中的一个得到分数恰好为k点,则这一局结束,双方得分重置并开始下一局比赛。

在所有的比赛中,teddy一共得了a分,小zc一共得了b分。综合这些信息,确定他们可能玩的最多的局数,或者这种情况是不可能的。

注意:每一局都是完整的,本游戏不同于真实的羽毛球规则,例如平衡规则(获胜一方至少比另一方多2)在这里不适用。(当然如果你们希望处理这个问题的话欢迎在赛后一起讨论)

 

输入描述:

多组输入,每组一行,包含空格隔开的3个整数kab(1<=k<=10^9,0<=a,b<=10^9,a+b>0)

 

输出描述:

如果情况不可能,输出单个数字-1,否则输出最多可能进行的局数。

 

输入样例:

21 21 15

21 2 3

 

输出样例:

1

-1

 

题目分析:

⾸先很⾃然想到贪⼼去做,统计teddy最多赢的次数和zc最多赢的次数,然后加起来就是最多可能的局数,然后排除掉样例中2⼈赢的次数为0的情况,然后提交返回wrong answer,原因在于少考虑⼀种情况,就是11 12 5这种情况,应该返回-1,很多代码返回了1,因为12%11=1,但是1凑不成完整的⼀局,这种情况只发⽣在a%k!=0&&b/k==0或者反过来,加上特判即可。

 

代码:

 

#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;long long int k,a,b;int main(){    //freopen("/Users/apple/Desktop/A、teddy打羽毛球input.txt","r",stdin);    //freopen("/Users/apple/Desktop/A、teddy打羽毛球output.txt","w",stdout);    while(cin>>k>>a>>b)    {        if(a<k&&b<k)        {            cout<<-1<<endl;            continue;        }        long long int p=0,q=0;        p=a/k;q=b/k;        int ya=a-p*k,yb=b-q*k;        if((ya!=0&&q==0)||(yb!=0&&p==0))        {            cout<<-1<<endl;            continue;        }        long long int sum=p+q;        cout<<sum<<endl;    }}

 

 

 teddy和箱子们

问题描述:

今天是teddy的生日,他收到了亲朋好友送来的一堆箱子装的礼物,假设箱子从1号到n号,他在每个箱子上面标上一个数字ai,并把他们排成一排,然后去出公差了。

这个时候,teddy的同学小zc对这些箱子进行重新排序,小zc使用如下规则进行排序,

1.  一共排序n/2

2.  i次排序将第i到第n-i+1个之间的箱子顺序反转一次

做完这些之后,小zc对自己的工作感到非常满意。当teddy回到自己箱子身边时发现箱子的顺序被改变了,请尽快帮teddy把箱子们恢复到原来的顺序。

 

输入描述:

输入包含多组数据。

每组数据第一行包含一个正整数n(1<=n<=2*10^5)

第二行包含n个整数a1a2,,,,an(-10^9<=ai<=10*9)ai是小zc更改顺序后第i个箱子的上的数字。

 

输出描述:

输出空格隔开的n个整数代表初始位置上顺序写在箱子上的数字。

 

输入样例:

7

4 3 7 6 9 12

8

6 1 4 2 5 69 2

 

输出样例:

2 3 9 6 7 14

2 1 6 2 5 49 6

 

HINT:

样例1中初始顺序为:2 3 9 6 7 1 4

第一次变换:4 1 7 6 9 3 2

第二次变换:4 3 9 6 7 1 2

第三次变换:4 3 7 6 9 1 2

最后一次变换:只有一个元素,所以位置不变。

 

题目分析:

模拟题,但是如果每次都把⼀整段反转⼀遍是O( n²/2 )的复杂度,显然超时,所以需要找规律,然后发现对于偶数位转到最后也没有变化,奇数为都中⼼对称的反转,所以此题O(n)的时间复杂度可解,注意⼤量数据输⼊需要使⽤scanf不能⽤cin,cin很慢的。

 

代码:

#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int num[200010];int n;int main(){    while(cin>>n)    {        for(int i=1;i<=n;i++)        {            scanf("%d",&num[i]);        }        for(int i=1;i<=(n-i+1);i++)        {            if(i&1) swap(num[i],num[n-i+1]);        }        for(int i=1;i<n;i++)        {            printf("%d ",num[i]);        }        printf("%d\n",num[n]);    }}



巨龙宝藏

 

问题描述:

       人类勇士zc终于打倒了恶龙救出了公主。zc和公主来到巨龙的巢穴,发现里面居然有一个巨大的宝藏!面对堆积成山的宝物,zc冷静得决定,每种宝物最多只取两样。

       由于每个宝物都有自己的价值,请你帮zc想想如何使取走的宝物价值最大。

 

输入描述:

       第一行为数据组数T。(1<=T<=1000

       对于每组数据——第一行为整数n,代表宝物的数量。(1<=n<=100)

       接下来n行,每行包括一个仅有’a’~’z’构成的长度不超过10的字符串s与一个正整数v。其中s为宝物的种类,v代表价值。相同的s代表相同种类的宝物。(1<=v<=1000)

 

输出描述:

       对于每组数据,输出一行,该行一个整数,代表zc可以取走宝物的最大价值。

      

输入样例:

       2

       5

       chayedan1

       chayedan2

       chayedan3

       huabanxie10

       qiegao100

       2

       a1

       a2

      

 

输出样例:

       115

       3

 

题目分析:

      每种宝物最多取两样,我们只需要对宝物进行排序(按照宝物名称的字典序+宝物价值从大到小的顺序)。然后从前到后扫一遍即可。

 

代码:

 

#include <iostream>#include<bits/stdc++.h>using namespace std;const int N=1100;struct node{    int v;    char s[20];}a[N];bool cmp(node a,node b){    if(strcmp(a.s,b.s)==0)    {        return a.v>b.v;    }    return strcmp(a.s,b.s)<0;}int main(){    //freopen("test.in","r",stdin);    //freopen("test.out","w",stdout);    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        for(int i=0;i<n;i++)        {            scanf("%s%d",a[i].s,&a[i].v);        }        sort(a,a+n,cmp);        int t;        int ans=0;        for(int i=0;i<n;i++)        {            if(i==0||strcmp(a[i].s,a[i-1].s)!=0)            {                ans+=a[i].v;                t=1;            }            else if(strcmp(a[i].s,a[i-1].s)==0&&t<2)            {                t++;                ans+=a[i].v;            }        }        cout<<ans<<endl;    }}

 


正义的伙伴


问题描述:

       在宇宙中有n颗邪恶星球,还有m颗光明星球。在邪恶星球和光明星球之间存在k条虫洞。

       正义的伙伴zc肩负着维护世界和平的任务。他有着神奇的能力能在虫洞中穿梭。当他从任意星球开始出发,穿过三条不同的虫洞时就可以使世界和平。

请你计算出zc完成任务的方案数。

       w1-b1-w2-b2为一种方案,其中w1-b1b1-w2w2-b2间存在虫洞。

 

输入描述:

       第一行输入数据组数T

       对于每组数据,第一行有三个整数nmk,表示n颗邪恶星球编号1~nm颗光明星球编号1~m,存在k个虫洞。(1 <=n , m , k <=100000

       接下来k行,每行两个整数xy,表示第x颗邪恶星球和第y颗光明星球之间存在虫洞。保证两颗星球之间的虫洞最多只有一个。

      

输出描述:

       对于每组数据,输出一行,该行包括一个整数,表示zc完成任务的方案数。

 

输入样例:

       3

       22 4

       11

       12

       21

       22

       31 3

       11

       21

       31

       33 3

       11

       21

       22

 

输出样例:

       8

       0

       2

 

Hint:

       第一组样例:(b1-w1-b2-w2) (b1-w2-b2-w1) (b2-w1-b1-w2) (b2-w2-b1-w1)(w1-b1-w2-b2) (w1-b2-w2-b1) (w2-b1-w1-b2) (w2-b2-w1-b1) 8种合法序列

 

题目分析:

      看完题目首先想到dfs,爆搜一下然后TLE一发。【由于时间设置比较宽,也能强行卡过去…】

首先这是一张二分图,每种情况由三条连续的线段组成。我们只需要考虑中间的那条线段。设线段X,X的两个端点为a、b。我们稍加思考可以发现,X作为中间线段所能产生的方案数为(a的度-1)*(b的度-1)。所以我们遍历所有的线段,将它们作为中间线段考虑即可。求和之后需要*2,(两个方向)。时间复杂度为o(k)。

 

代码:

#include <iostream>#include<bits/stdc++.h>#define ll __int64using namespace std;const int N=110000;int dl[N],dr[N],l[N],r[N];int main(){    //freopen("test.in","r",stdin);    //freopen("test.out","w",stdout);    int T;    scanf("%d",&T);    while(T--)    {        int n,m,k;        scanf("%d%d%d",&n,&m,&k);        memset(dl,0,sizeof(dl));        memset(dr,0,sizeof(dr));        for(int i=0;i<k;i++)        {            scanf("%d%d",&l[i],&r[i]);            dl[l[i]]++;            dr[r[i]]++;        }        ll ans=0;        for(int i=0;i<k;i++)        {            ll ld=dl[l[i]],rd=dr[r[i]];            ans+=(ld-1)*(rd-1);        }        ans*=2;        printf("%I64d\n",ans);    }}


最小、大公因数

 

问题描述:

⼏⾥得算法称辗转相除法,于计算两个正整数ab的最公约数。

⼏⾥得算法产的背景:

我们知道,约公元前300年,古希腊著名数学家欧⼏⾥得在前基础上写成的不配

名著《何原本》,乎包括了中学所学习的平⾯⼏何、何的全部内容。如

此古何内容,然成了历次数学课程改关注的焦点。其中最为激进的,如法

国布尔巴基学派主要物狄奥东尼甚喊出了“欧⼏⾥得滚出去”的号。但改来改

去,欧⽒⼏何的些内容,仍然构成了多数国家中学数学何部分的主要内容。有

称之为“不倒翁现象”。

给你n0的数字,问它们的最、最公因数的乘积是多少? 最后对结果

mod 17

 

输入描述:

数字n,紧接着n个数字a1<n<150<a<100

 

输出描述:

输出n个数字最公因数的乘积。

 

输入样例:

2

1 2

 

输出样例:

1

 

题目分析:

题⽬中主要涉及⼀个知识点:最⼤公因数的求法(gcd算法)。题⽬还提到求最⼩公因数,这个⼀般来说认为1就不需要求了。于是只需要连续求n个数的最⼤公因数即可:

⾸先考虑两个数的最⼤公因数定义:

其中q为素数

那么可以推出多个数的最⼤公因数:

gcd算法算法复杂度推倒可以类⽐斐波那契数列,复杂度为log(Max(a,b)),题⽬整体的复杂度为:n*log(Max)

 

代码:

#include <iostream>using namespace std;int gcd(int a,int b){    return b==0?a:gcd(b,a%b);}int main(int argc,const char*argv[]){    int n;    while(scanf("%d",&n)!=EOF){        int a[20];        for(int i=0;i<n;i++) cin>>a[i];        int d=a[0];        for(int i=1;i<n;i++) d=gcd(d,a[i]);        cout<<d%17<<endl;    }    return 0;}





 

1 0
原创粉丝点击