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;
}