好久没写博客了。。。。
这次是大学后第一次博客,用来总结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],表示这个格子能获取的能量
输出
输出结果为一个数字,代表机器人最少需要有多少的初始能量
样例输入
5
1
-2
-1
3
4
样例输出
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:三角
题目描述
将1,2,······,9共9个数排成下列形态的三角形。
a
b c
d e
f g h i
其中:a~i分别表示1,2,······,9中的一个数字,并要求同时满足下列条件:
(1)a<f<i;
(2)b<d, g<h, c<e
(3)a+b+d+f=f+g+h+i=i+e+c+a=P
输入
边长之和P
输出
所有满足上述条件的三角形的个数以及其中的一种方案。
若有多种方案输出字典序最小的那种。若无解输出NO。
样例输入
21
样例输出
4
3
2 4
9 6
7 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行,每行一个正整数N。
1 <= T <= 100000
1 <= N <= 10000000
输出
T行每行一个整数表示答案。
样例输入
1
3
样例输出
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
单样例
输入
n
x1x2...xn
输出
n行,每行一个输出"YES"或"NO"(不包括引号)
样例输入
2
3 6
样例输出
YES
NO
还是一个判断奇偶的题目。似乎不用解释了。签到题(虽然数据开始也是错的。。。。)
不会的回去补数学去。
#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行按照升序打印满足要求的数字
样例输入
21
20
样例输出
1
15
0
提示
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);
}
}
大体就这样了。除了一堆数据问题,这次月赛还是有许多特别水(暴力)的题目的。