buct12月月赛总结

来源:互联网 发布:郑州淘宝网店加盟被抓 编辑:程序博客网 时间:2024/04/30 15:49

好久没写博客了。。。。

这次是大学后第一次博客,用来总结12月月赛。8道A了6道。AB等补充。

题C:机器人

题目描述有编号1-n的n个格子,机器人从1号格子顺序向后走,一直走到n号格子,并需要从n号格子走出去。机器人有一个初始能量,每个格子对应一个整数A[i],表示这个格子的能量值。如果A[i] > 0,机器人走到这个格子能够获取A[i]个能量,如果A[i] < 0,走到这个格子需要消耗相应的能量,如果机器人的能量 < 0,就无法继续前进了。问机器人最少需要有多少初始能量,才能完成整个旅程。例如:n = 5。{1,-2,-1,3,4} 最少需要2个初始能量,才能从1号走到5号格子。途中的能量变化如下3 1 0 3 7。1e9>=n>=1-1e5<=A[i]<=1e5输入给定一个n,接下来n行,每行一个数字,第i行的数字是A[i],表示这个格子能获取的能量输出输出结果为一个数字,代表机器人最少需要有多少的初始能量样例输入51-2-134样例输出2

怎么说呢?这是一个大暴力。从最少的初始能量就是保证途中能量最小值为0。也就是说,初始能量就是途中能量最小值的相反数。因此,我们有了时间复杂度为n的算法。唯一的坑就是,数据需要longlong存。

#include<iostream>#include<algorithm>#include<cstdio>#include<queue>#include<stack>#include<cstring>#include<cmath>using namespace std;//不要在意这么多头文件int main(){    long long t,min=0,k,sum=0;    scanf("%lld",&t);    while(t--)    {        scanf("%lld",&k);        sum+=k;        if(min>sum)min=sum;    }    printf("%lld",-min);    return 0;//不需要解释了} 

题D:最后一个是谁?题目描述
有n个人围成一圈,顺序排号。从第一个人开始报数(第一个报1,第二个报2……),凡报到m的人退出圈子(下一个人从1开始报),问最后留下的是原来第几号的那位。
输入
多组测试数据 t;
第一行输入t,1<=t<=10.
接下t行,每行两个整数,n,m 1<=n<=1000,1<=m<=1000.
输出
输出t行,每行一个整数。
样例输入
2
468 335
501 170
样例输出
88
393瑟夫问题,不解释。

#include<iostream>#include<algorithm>#include<cstdio>#include<queue>#include<stack>#include<cstring>#include<cmath>using namespace std;//说了不要在意头文件int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m,s=0;        scanf("%d%d",&n,&m);        for(int i=2;i<=n;i++)        s=(s+m)%i;        printf("%d\n",s+1);    }} 

题E:三角

题目描述   将12,······,99个数排成下列形态的三角形。ab cd ef g h i其中:a~i分别表示12,······,9中的一个数字,并要求同时满足下列条件:(1a<f<i;2)b<d, g<h, c<e(3a+b+d+f=f+g+h+i=i+e+c+a=P输入边长之和P输出所有满足上述条件的三角形的个数以及其中的一种方案。若有多种方案输出字典序最小的那种。若无解输出NO。样例输入21样例输出432 49 67 1 5 8

这是一个很坑的问题:由于数据问题,现场没有一个Ac的。赛后改了数据,全场一个两个Ac的。另一个学号还特别诡异。其实,还是一个大暴力。一个数组标记每个数是否使用过了。或者最后判断a+b+c+d+e+f+h+i==55&&a*b*c*d*e*f*g*h*i==1*2*3*4*5*6*7*8*9
或者选择打表。
唯一的问题就是代码很长。

#include<iostream>#include<algorithm>#include<cstdio>#include<queue>#include<stack>#include<cstring>#include<cmath>using namespace std;int flag[10];int run(int p){    memset(flag,0,sizeof(flag));//memset是初始化    int find=0;    for(int a=1;a<8;a++)//这段是计数    {        flag[a]=1;//标记a用过了。下同。        for(int b=1;b<9;b++)        if(flag[b]==0)        {            flag[b]=1;            for(int c=1;c<9;c++)            if(flag[c]==0)            {                flag[c]=1;                for(int f=a+1;f<9;f++)                if(flag[f]==0)                {                    flag[f]=1;                    for(int i=f+1;i<10;i++)                    if(flag[i]==0)                    {                        flag[i]=1;                        for(int g=1;g<9;g++)                        if(flag[g]==0)                        {                            flag[g]=1;                            int d=p-a-b-f,h=p-i-g-f,e=p-i-c-a;                            if(flag[d]==0&&flag[h]==0&&flag[e]==0&&d!=e&&h!=e&&d!=h&&b<d&&g<h&&c<e&&a<10&&b<10&&c<10&&d<10&&i<10&&f<10&&g<10&&h<10&&e<10)find++;//冗长的判断                            flag[g]=0;//回复g初始状态,下同                        }                        flag[i]=0;                    }                    flag[f]=0;                }                flag[c]=0;            }            flag[b]=0;        }        flag[a]=0;    }    if(find==0)    {        printf("NO\n");        return 0;    }    printf("%d\n",find);    for(int a=1;a<8;a++)//这段是输出最小字典序    {        flag[a]=1;        for(int b=1;b<9;b++)        if(flag[b]==0)        {            flag[b]=1;            for(int c=1;c<9;c++)            if(flag[c]==0)            {                flag[c]=1;                for(int f=a+1;f<9;f++)                if(flag[f]==0)                {                    flag[f]=1;                    for(int i=f+1;i<10;i++)                    if(flag[i]==0)                    {                        flag[i]=1;                        for(int g=1;g<9;g++)                        if(flag[g]==0)                        {                            flag[g]=1;                            int d=p-a-b-f,h=p-i-g-f,e=p-i-c-a;                            if(flag[d]==0&&flag[h]==0&&flag[e]==0&&b<d&&g<h&&c<e&&a<10&&b<10&&c<10&&d<10&&i<10&&f<10&&g<10&&h<10&&e<10&&d!=e&&h!=e&&d!=h)                            {                                printf("%d\n%d %d\n%d %d\n%d %d %d %d\n",a,b,c,d,e,f,g,h,i);                                return 0;                            }                            flag[g]=0;                        }                        flag[i]=0;                    }                    flag[f]=0;                }                flag[c]=0;            }            flag[b]=0;        }        flag[a]=0;    }}int main(){    int p;    while(scanf("%d",&p)!=EOF)    run(p);}

F: 室友A的PY交易

题目描述CC和TT在宿舍忙着写课设,他们决定由下述游戏的败者去拿外卖:室友A想一个[1,N]中的数字X,两人轮流猜一个猜一个数字,恰好猜中X的人算负;否则室友A将告诉两人当前猜的数字是比X大还是比X小,这样一来猜测的范围就会变小(下一轮猜的数必须在X所在的那一半区间内)。初始范围是[1,N]。室友A已经看透了一切,私下告诉了两人X是多少。现在,CC和TT都知道X是多少,且两个人都采取最优策略。若总是CC先猜,求X∈[1,N]可以使TT获胜的X的数量。输入第一行一个整数T表示数据组数。接下来T行,每行一个正整数N1 <= T <= 1000001 <= N <= 10000000输出T行每行一个整数表示答案。样例输入13样例输出1

这是一个博弈论的题目。
先说答案。如果是偶数那么结果是0。如果是奇数,那么结果是1。唯一的结果就是x在1和n最中间。
具体最佳解法就是对称。当对称时,无论TT从左边取多少,CC就从右边取多少。这样取到最后,左右都没有数,TT就必须选择x,然后GG。
因此,对称时必败状态。所以,所有能到必败状态的都是必胜状态。即,不对称是必胜的。然而——
CC先取数。CC可以一下子取到对称。
因此,只有对称是TT能获胜的状态。
时间复杂度1

#include<iostream>using namespace std;int main(){    int t;int k;    cin>>t;    while(t--)    {        scanf("%d",&k);        printf("%d\n",k&1);//这是位运算。。。懒得改了。。。就是判断奇偶。奇输出1,偶0    }   }

题 G: 小明的游戏

题目描述小明喜欢数字,现在小明想把一个数字拆分成若干个奇数的乘积,但他不知道能不能拆分成功,你能帮帮他么给你n个数,每个数都在int范围内0<n<=1e5单样例输入nx1x2...xn输出n行,每行一个输出"YES""NO"(不包括引号)样例输入23 6样例输出YESNO

还是一个判断奇偶的题目。似乎不用解释了。签到题(虽然数据开始也是错的。。。。)
不会的回去补数学去。

#include<cstdio>int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m,s=0;        scanf("%d",&n);        if(n&1)printf("YES\n");        else printf("NO\n");    }} 

题 H: 值日生

题目描述八年级的Vova今天在课堂上值班。上课之后,他走进办公室洗板子,并在上面找到了n号。他问这个数字是什么,数学老师Inna Petrovna回答Vova说,n是一年级学生算术任务的答案。在教科书中,给出了某个正整数 x。n为十进制x加上各位上的数字的 和。由于数字n很小,Vova很快就猜到了在教科书中可能出现哪个x。现在他想得到一个程序,它将搜索任意值为n的所有合适的x值,或者确定这个x不存在。为Vova写一个这样的程序输入第一行包含整数n(1≤  n  ≤10^9)。输出在第一行打印一个整数k  表示满足要求的方案 后k行按照升序打印满足要求的数字样例输入2120样例输出1150提示15+1+5=21,只有一个满足要求

对于本蒟蒻而已,这个题似乎没有规律。由于n的数字很小(嗯,10^9),所以特别暴力就会TLE(time limit exist)。因此,不能从1开始筛。
读题。一个小于10^9的数字,加上每一位。一共不超过10位,每位小于10,因此x与n的差一定小于100。剩下的,就是100个数分别求其加每一位的值。很暴力吧?
为了省时间,使用了queue。

#include<iostream>#include<algorithm>#include<cstdio>#include<queue>#include<cstring>#include<cmath>using namespace std;int find(int n){    queue<int>q;    int k=n;    for(int i=k-100;i<k;i++)    {        int j=i,p=i;//防止i被破坏        while(j)        {            p+=j%10;            j/=10;        }        if(p==n)q.push(i);    }    cout<<q.size()<<endl;//输出大小    while(!q.empty())    {        printf("%d\n",q.front());        q.pop();    }}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        find(n);    }}

大体就这样了。除了一堆数据问题,这次月赛还是有许多特别水(暴力)的题目的。