A Even But Not Even
链接:http://codeforces.com/contest/1291/problem/A
题意 :给你一个数字 删去任意数字(可以不删)后 使得这个数字是奇数 各个位数和是偶数(不包含前导0)
思路:开个数组保存前缀和 向后遍历 标记一个前面的奇数 如果遍历到某一位后 这位数是奇数 前缀和是偶数 那么全部输出 如果前缀和是奇数 把标记的奇数删除
听说了一个思路 找两个奇数 就好了 tql
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int main()
{
int t,n;
char s[N];
cin>>t;
while(t--)
{
cin>>n>>s+1;
int sum[N];
sum[0]=0;
int j=-1;
bool flag=0,flag1=0;
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+s[i]-'0';
if(j!=-1&&sum[i]&1&&(s[i]-'0')&1)
{
n=i;
flag=flag1=1;
break;
}
if(sum[i]%2==0&&(s[i]-'0')&1)
{
n=i;
flag=1;
break;
}
if(j==-1&&(s[i]-'0')&1)j=i;
}
if(flag)
{
if(flag1)
for(int i=1;i<=n;i++)
if(j==i) continue;
else
cout<<s[i];
else
for(int i=1;i<=n;i++)
cout<<s[i];
cout<<endl;
}
else cout<<-1<<endl;
}
return 0;
}
B. Array Sharpening
链接:http://codeforces.com/contest/1291/problem/B
说起b题就是一把伤心泪啊 先是看错题意 发现错了后又东改西改 越改越乱 哎还是太菜了
题意给你一个数组 你可以选择任意一个正数把它-1 (任意次 只要是正数)
问你是否可以把它变成一个前半部单调递增后半部单调递减的数组 (单调递增,单调递减也都可以)
从前向后遍历 cnt保存前部分有多少个负数 那么 下标为cnt+1的地方就是0出现的位置 那么 第i位置的最小值就是 i-cnt -1 找到不满足的地方 保存为l。l-1就是前半部分最长的单增长度 同理 从后向前遍历找到最大的单减位置是r+1 如果 l-1>=r+1 即
l>=r+2就是两段区间有交集 就符合题意了 还有如果 l或者r没有更新过那么就是可以变成一个完全单调的数组。满足三者中的一个就可以了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300010;
int main()
{
int t,n;
int s[N];
s[0]=-1;
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>s[i];
int l=0,r=n+1,t,cnt=0;
for(int i=1;i<=n;i++)
{
if(i==1)
{
if(s[1]<0) cnt++;
continue;
}
if((s[i]>0&&s[i]<i-cnt-1)||(s[i]<=0&&s[i]<=s[i-1]))
{
l=i;
break;
}
if(s[i]<0&&s[i]>s[i-1])
cnt++;
}
cnt=0;
for(int i=n;i>0;i--)
{
if(i==n)
{
if(s[i]<0) cnt++;
continue;
}
if((s[i]>=0&&s[i]<n-i-cnt)||(s[i]<=0&&s[i]<=s[i+1]))
{
r=i;
break;
}
if(s[i]<0&&s[i]>s[i+1])
cnt++;
}
if(!l||r==n+1||l>r+1) cout<<"Yes"<<endl;//区间[1,l-1]与区间[r+1,n]有交集
else cout<<"No"<<endl;
}
return 0;
}
C :http://codeforces.com/contest/1291/problem/C
题意:共有n个数字 m个人 每个人可以从数组序列的头部或者尾部拿走一个数字 你是第m个 但是你有个特权可以指定前k个人拿那些数,问在这样的条件下你一定能拿到的数的最小值(就是说你拿到的数一定比它大,使这个数最大化)
观察之后会发现前k个人指定后 剩余的数字的长度是不变且连续的 就是
区间[1,n-k] ->区间 [ k+1,n] 这些个区间就是指定后k后剩余的所有情况了
每个区间先求最小值 再在这些值中求最大值
那么问题就是每个区间阿怎么求最值了
现在就要分两种情况 如果 m < k 那么就要在这些区间上随机的选m-k 次了
假设在区间[l,r]上选k次那么前k-1次选择后剩下的数字还是长度不变且连续的区间了
区间[l,r-k+1] -> [l+k,r] 枚举每个区间 在区间两端取最大的那一个 在这几个区间内取最小值 就在区间[l,r] 上取k次的最小值了
然后 如果 m>=k 那么就不用指定k个人了 只用指定 m-1个 所以把上的 k 换成m-1就行了 就是在枚举的区间内都取一次
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3560;
int t,n,m,k,s[N];
int check(int l,int r,int k)在区间[l,r]内取k次取得的最小值
{
int res=0x3f3f3f3f;
for(int i=l;i<l+k;i++)
res=min(res,max(s[i],s[i+r-l-k+1]));每个区间两端取最大值 所有区间取最小值
return res;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m>>k;
int ans=0;
for(int i=0;i<n;i++)
cin>>s[i];
if(m>k)
for(int i=0;i<=k;i++)
ans=max(ans,check(i,n-k+i-1,m-k));
else
for(int i=0;i<=m-1;i++)
ans=max(ans,check(i,n-m+i,1));
cout<<ans<<endl;
}
return 0;
}