习题训练计划 2020 06 09
A题:
题意就是给你一个n和一个k,然后判断n是否能由k个比n小的不同奇数组成。
即n=a1+a2+……+ak,ai为奇数
思路:找规律。
如果k是1,等号右边只有一个奇数,那么n一定为奇数。
如果k是2,等号右边为 奇数+奇数 =偶数,所以n一定为偶数。
如果k是3,等号右边为 偶数+奇数 =奇数,所以n一定为奇数。
如果k是4,等号右边为 奇数+奇数 =偶数,所以n一定为偶数
……
不难发现,当k为奇数是,n必须要为奇数,k为偶数时,n必须要为偶数。
另外,前k个奇数(最小的k个奇数)的和为k*k,也就是说n如果小于k*k,那么一定不可以,所以n>=k*k。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200000+8],b[200000+8];
int main()
{
ll t,n,k,i;
cin>>t;
while(t--)
{
scanf("%lld%lld",&n,&k);
if((n&1)==(k&1)&&n>=k*k)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
B题:
模拟题。
思路:对于每一个样例,遍历他的所有的女儿,如果这个女儿能和清单上的某一个王子结婚,就把该王子置为1,并让结婚女儿的数量num++,如果这个女儿没有结婚,就记录下这个女儿的编号ans1(最终我们得到的是没有结婚的第一个女儿的编号),如果num==年,也就是说所有的女儿都结婚了,那么直接输出“OPTIMAL”即可,否则,我们便遍历所有的王子,直到找到第一个等于0的王子,用ans2记录下该王子的编号,最后输出“IMPROVE”和ans1,ans2即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100000+8]={0};
int main()
{
int t;
cin>>t;
while(t--)
{
int n,i,j,k;
memset(a,0,sizeof(a));
int ans1=0,g=1;
scanf("%d",&n);
int num=0;
for(i=1;i<=n;i++)
{
scanf("%d",&k);
int f=1;
for(j=1;j<=k;j++)
{
int x;
scanf("%d",&x);
if(a[x]==0&&f==1)
{
a[x]=1;
f=0;
num++;
}
}
if(f==1&&g)
{
ans1=i;
g=0;
}
}
if(num==n)
{
cout<<"OPTIMAL"<<endl;
}
else
{
int ans2=0;
for(i=1;i<=n;i++)
{
if(a[i]==0)
{
ans2=i;
break;
}
}
cout<<"IMPROVE"<<endl;
cout<<ans1<<' '<<ans2<<endl;
}
}
return 0;
}
C题:
刚开始以为是数学规律,找了半天规律。
思路:gcd(x-1,1)=1,lcm(x-1,1_)=x-1,所以我们只需要输出1和x-1就行了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200000+8];
int main()
{
int t,i,j,k,n,x;
cin>>t;
while(t--)
{
scanf("%d",&x);
cout<<1<<' '<<x-1<<endl;
}
return 0;
}
D题:
通过把所给数组不断的重复组合,我们实际上可以得到的最长增字串为数组中所有不同的数从小到大排列,所以答案就是所给数组中不同数字的个数。我是用set来去重,最后输出set.size()即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200000+8];
int main()
{
int t,n,i,j,k,m;
cin>>t;
while(t--)
{
set<int>h;
scanf("%d",&n);
for(i=0;i<n;i++)
{
cin>>m;
h.insert(m);
}
cout<<h.size()<<endl;
}
return 0;
}
E题:
F题:
要想最后消去所有的方块,我们可以先执行第一步,不断的加方块,直到所有地方的高度相同,再执行第二部,一次性消除所有的方块。
所以,我们只需要找到所给数组中的最大值,然后判断数组中的每个数是否可以通过不断加2达到最大值(即max-a[i]是否是2的倍数),如果数组中所有的数都满足这个条件,那么我们就可以达到目的,消除所有的方块,输出“YES”,反之输出“NO”。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200000+8];
int main()
{
int t,n,i,j,k,m;
cin>>t;
while(t--)
{
scanf("%d",&n);
int ma=0;
for(i=0;i<n;i++)
{
cin>>a[i];
if(a[i]>ma)
{
ma=a[i];
}
}
for(i=0;i<n;i++)
{
if((ma-a[i])%2!=0)
{
break;
}
}
if(i==n)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
G题:
找长度至少为3的回文子串,所以我们只需要找到长度为3的回文子串即可(因为长度大于3的回文子串一定包含长度为3的回文子串),而长度为3的回文子串的一大特点就是地个数和第三个数相等,所以我们只需要在所给数组中找到两个不相邻但相等的数即可,此外n和t都不大,所以直接暴力就行。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200000+8];
int main()
{
int t,n,i,j,k,m;
cin>>t;
while(t--)
{
cin>>n;
bool flag =0;
for(i=0;i<n;i++)
{
cin>>a[i];
for(j=0;j<i-1;j++)
{
if(a[j]==a[i])
{
flag=1;
break;
}
}
}
if(flag==1)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
H题:
青蛙从0的位置开始向右跳,目标是n+1的位置,要想向右跳,他必须落到‘R’上面,即便像样例一那样落到了‘L’上面,下一步也是要回到‘R’上面,所以我们可以让青蛙一直呆在’R上面,也就是说青蛙奔向目标的过程是从一个‘R’转移到另一个‘R’,最终到达n+1的过程,所以我们只需要找到0,n+1,以及所有R之间的距离的最大值即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100000+8]={0};
int main()
{
int t,n,i,j,k;
cin>>t;
while(t--)
{
string s;
cin>>s;
int p=0,ans=0;
int len=s.size();
int m;
for(i=0;i<len;i++)
{
if(s[i]=='R')
{
m=i+1;
m=m-p;
ans=max(ans,m);
p=i+1;
}
}
m=len+1;
m=m-p;
ans=max(ans,m);
printf("%d\n",ans);
}
return 0;
}