题目传送门:https://codeforces.com/contest/1291/
A. Even But Not Even(思维+前缀和)
题目大意:
给你一串数字,问你能不能通过去掉几个数字(也可以一个都不去)来将这个数变成一个所有数字之和是偶数且这个数本身是个奇数的。比如123就是这样的数字。
如果可以的话输出这个数字,如果不能的话输出-1,同一串数字可能有多个结果,输出任意一个均可。
题目分析:
用一个数字记录一下前缀和,也就是从开头一直加到当前数字的值(用于判断到当前位置数字之和是不是偶数),然后判断原数字的这一位上是不是奇数。倒着往前遍历,如果能找到,满足题意的情况,从头输出到当前为即可。如果遍历结束还没有找到满足题意的情况,输出-1;
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
using namespace std;
int main()
{
static char a[3010]={0};
static int b[3010]={0};
static int c[3010]={0};
int t=0,n=0;
cin>>t;
while(t--)
{
scanf("%d",&n);
scanf("%s",&a);
for(int i=0;i<n;i++)
b[i]=a[i]-'0';
c[0]=b[0];
for(int i=1;i<n;i++)
{
c[i]=c[i-1]+b[i];
}
int k=n-1;
while(k>=0)
{
if(c[k]%2==0&&b[k]%2==1)
{
for(int i=0;i<=k;i++)
printf("%d",b[i]);
printf("\n");
break;
}
k--;
}
if(k<0)
{
cout<<-1<<endl;
continue;
}
}
return 0;
}
B. Array Sharpening(思维)
题目大意:
给你一个数组,里面有n个数字,里面数字的大小只能减少或者不变但不能增加,问这一个数组通过许多次变化变成满足a1<a2<…<ak 而且 ak>ak+1>…>an的情况。也就是说类似于一个山峰,中间最高,两边依次下降。注意只有一个数字的时候是满足题意的。
题目分析:
通过分析题目我们可以知道,如果里面有3个数字,那么010是最小的可能满足题意的情况。同样的,如果有4个数字,那就是0120,0210这三种最小的情况。如果是5个数字,那就是01210是最小的情况。
所以,我们不妨先生成一个n个数字最小情况,然后按位去跟所给的数组进行比较,如果所给的数组中有比最小情况还小的数字,那必定不满足,否则就是满足。但是n为奇数的时候好办,n为偶数时我们生成的最小序列是0110,但是这个序列并不满足题意,因为1=1,不是大于,所以生成最小序列的最大数的时候要把n为奇数和n为偶数的情况分开考虑。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
using namespace std;
int main()
{
int t=0,n=0;
cin>>t;
static int a[300010]={0};
static int b[300010]={0};
while(t--)
{
int flag=1;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
if(n==1)
{
printf("Yes\n");
continue;
}
if(n==2)
{
if(a[0]==0&&a[1]==0)
{
printf("No\n");
continue;
}
else
{
printf("Yes\n");
continue;
}
}
if(n==4)
{
if(a[0]==0&&a[1]==1&&a[2]==1&&a[3]==0)
{
printf("No\n");
continue;
}
}
int k=0;
for(int i=0;i<n/2;i++)
{
b[i]=i;
}
for(int i=n-1;i>n/2;i--)
{
b[i]=k;
k++;
}
if(n%2==1)
b[n/2]=ceil(n/2);
else
b[n/2]=b[n/2-1];
for(int i=0;i<n;i++)
{
if(a[i]<b[i])
{
flag=0;
break;
}
}
if(n%2==0)
{
if(a[n/2]<=b[n/2]&&a[n/2-1]<=b[n/2-1])
flag=0;
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
C. Mind Control(暴力+思维)
题目大意:
给你n个数字,每个人按照顺序去取一个数字,只能取第一个或者最后一个数字,你是第m个去取数字的人,你能控制k个人的思维指定他们去取第一个或者最后一个数字。没有被你控制的人可以随便取。问你在所有的可能中,你能取到的数字的最小值中的最大值是多少?
题目分析:
如果k>=m的话,令k=m-1。如果你是第m个取的,你控制前面m-1个人的思维就好了,你后面的人怎么取雨女无瓜。然后进一步更新m,让m为减去你控制的k个人和你自己(因为你自己受你自己控制)剩下能够随便取的人的个数。然后比较这m个情况里你能取到的最小值,从中选出一个最大的。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int t,n,a[3505],m,k,ans;
int Judge(int left,int right,int x)
{
int temp=1e9;
for(int i=0;i<=x;i++)
{
temp=min(temp,max(a[left+i],a[right-x+i]));//left+i是队首,right+i-x是队尾
}
return temp;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
if(k>=m)
k=m-1;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
m=m-k-1;//除去自己指定的人选择,还有自己选择的那一次,其余随意选择的人的个数
ans=0;
for(int i=0;i<=k;i++)
{
ans=max(ans,Judge(i+1,n-k+i,m));
}
printf("%d\n",ans);
}
return 0;
}
小结:
今天又被怼怼了,还是要好好练习算法,思维和算法一样都不能落下。