Codeforces Round 884 (Div. 1 + Div. 2) A-D 题解
A:
题意:给你两个数a,b(a<b),两个人可以选择拿a个石头或者拿b个石头,现在让你给出石头的数量,让在这种情况下后手必胜(无法拿石头的一方输。)
提示:这里可以添加学习目标
思路:
因为已知a,b石头的大小关系,那么只要
a不为1,使石头数量为1,这样先手拿不了自然赢;
~~
如果a为1,
~~~~
那么看如果2*a<=b,即b大于2的话,直接使石头为2即可。
~~~~
否则b小于2,但是b又大于1,那么b只能为2,直接输出3.
代码:
void slove( )
{
int t;
int a,b;
cin>>a>>b;
if(a==1&&b==2)
cout<<3;
else if(a==1)
cout<<2*a;
else cout<<a-1;
cout<<endl;
}
B:
题意:让你构造一个长度为n的排列,同时使这个排列内的MES值尽可能大,
MES代表 代表不出现在区间中的最小正整数。
思路:
ps:(当时写b题的时候脑袋太蠢了一直卡着导致心态崩了,现在感觉还是想太多/没想到点子上)。
因为要使MES达到最大,那么就要使质数尽可能出现的少,那么非质数就出现的最多,
那么对于第一个非质数1,就要尽可能出现的多在子序列中,那么1是肯定需要放在最中间的。
然后在1已经在中间的前提下,如果数组内不存在2或者3,那么MES一直是质数即是一个合法的答案
如果数组没包含1,那么MES为1,无论怎么放置都是一个无效的答案
如果数组里包含1,那么如果把2和3放在最前面和最后面,那么只要不是区间为[1,n]
那么将都是一个合法的答案。
所以只需要将1,2,3的位置放好,那么其他数完全可以随便放,这种情况就是最优的情况
代码:(用的cf官方代码自己的写的依托答辩)
#include <bits/stdc++.h>
using namespace std;
int a[200000];
int main() {
int i;
int t,n;
scanf("%d",&t);
while (t--) {
scanf("%d",&n);
if (n == 1) printf("1\n");
else if (n == 2) printf("1 2\n");
else {
int c = 4;
fill(a,a+n,0);
a[0] = 2,a[n/2] = 1,a[n-1] = 3;
for (i = 0; i < n; i++) {
if (a[i] == 0) a[i] = c++;
}
for (i = 0; i < n; i++) printf("%d%c",a[i],(i == n-1) ? '\n':' ');
}
}
return 0;
}
C:
题意:给定一个长度为n的序列,你可以进行任意次以下操作:
选择一个元素并删除它,之后使它两边的元素合并成一个元素,值为两者之和
问你最后的元素最大可能为多少。
思路:
自己模拟了之后可以发现,对于某一个元素进行操作时,剩下的所有元素的下标的奇偶性都不发生改变。那么这个有什么用呢,再仔细点我们可以发现,我们合并的两个元素,他们之间的下标的奇偶性是一致的。
那么得出结论,对于长度为n的序列,只有下标的奇偶性一致的元素才可以被合并在一起,那么直接比较只加偶数和只加奇数的情况的和,取最大值就可以了(下标的奇偶)。
因为要取最大值,那么对于负数可以直接删除。
同时如果全为负数,需要留一个最大的负数作为答案。
代码:
void slove( )
{
int t;
cin>>n;
vector<ll>q;
bool st=0;
for(int i =1;i<=n;i++){
cin>>s[i];
if(s[i]>0)st=1;
}
if(st==0){//全是负数
ll res=-1e18;
for(int i =1;i<=n;i++)
res=max(res,s[i]);
cout<<res<<endl;
return ;
}
ll res1=0,res2=0;
for(int i =0;i<q.size();i+=2) if(q[i]>0) res1+=q[i];
for(int j =1;j<q.size();j+=2) if(q[j]>0) res2+=q[j];
cout<<max(res1,res2);
cout<<endl;
}
D:
题意:给你一个字符串的长度n,把这个字符串连续的分成a行b列的二维字符串(a*b==n),并且要求每个字符的相邻字符都不相同。让你输出这个字符串,并且这个字符串的字符种类最少。
思路:
这里借了个图对于相邻字符不 同的解释:
对于一个长度为m的字符串s,如果是字符串总长度为n的因子,
没有一个可以整除m,那么这个字符串就是一个合法的。
那么可以先求出来一个最短的字符串k,然后以这个字符串为模板不断增加就好。
(比如n是8,因子为1 2 4 8,最小m的长度为3,那么可以为abc,然后以此为循环节增加,如果会产生相邻字符相同的情况下,那么即k[i]=k[i+3*x],x为1,2…), 但是n中不存在3的因子,那么abc就是合法且最短的一个循环节)。
代码:
void slove( )
{
int t;
sc_int(n);
int sum=n;
s[0]='a';
for(int i =1;i<=n;i++)
{
s[i]=s[i-1]+1;
if(n%i!=0){
sum=i;
break;
}
}
for(int j =0,i=1;i<=n;i++,j=(j+1)%sum)
{
cout<<s[j];
}
cout<<endl;
}
ps:继续打吧,毕竟还能顺便陪陪对象(bus)