Codeforces Round 866 (Div. 2) A~C
这场,非常快落!是难得对中国选手友好的时间(17:05)
A观察一下,发现在连续的___中插入^就好,然后特判一下首尾,发现很像小学奥数的那个植树问题哇(
注意特判一下只有一个^
#include<bits/stdc++.h> using namespace std; void solve(){ string s; cin>>s; int n=s.length(); int ans=0; if(n==1&&s[0]=='^') { cout<<1<<endl;return; } if(s[0]=='_') ans++; if(s[n-1]=='_') ans++; int pre=0; for(int i=0;i<n;i++){ if(s[i]=='_') pre++; else { //cout<<i<<" "<<pre<<endl; ans+=max(pre-1,0); pre=0; } } ans+=max(pre-1,0); cout<<ans<<endl; } int main(){ //freopen("lys.in","r",stdin); int t; cin>>t; while(t--){ solve(); } }
B的话是观察了样例后猜的结论,但是越猜越对,最开始感觉只跟最长的连续1有关(因为只要有0就断掉了)
然后考虑一下如果有一段连续1,会怎么操作?其实是慢慢挪动,有一个错位的效果
假如有4个1,那么有5=1+4,5=2+3,5=3+2,5=4+1,矩形的面积可能有1*4,2*3
显然和一定,两个数尽量相近的时候取最大。
但光是这样是过不了样例的,因为存在特殊情况使得头和尾都是1,这种情形下其实是连在一起的
那就破环成链,复制一遍后再算
但这样又会wa2,测了一个全是1的样例,发现这样会多算,所以还要特判是否全为1
然后在跌跌撞撞的猜测和快落的讨论中,虽然对结论不是很有底,竟然Accepted了
#include<bits/stdc++.h> using namespace std; int main(){ //freopen("lys.in","r",stdin); int t; cin>>t; while(t--){ string t,s; cin>>t; s=t+t; long long n=t.length(),pre=0,mx=0; if(n==1){ if(s[0]=='1') cout<<1<<endl; else cout<<0<<endl; continue; } for(int i=n;i<2*n;i++) s[i]=s[i-n]; if(s[0]=='1') pre=1,mx=1; for(int i=1;i<2*n;i++){ if(s[i]=='1'){ pre++; mx=max(pre,mx); } else pre=0; } if(mx==2*n){ cout<<n*n<<endl; continue; } mx++; if(mx%2==0) cout<<mx*mx/4<<endl; else cout<<(mx/2)*(mx/2+1)<<endl; } }
C的题目名字告诉你,这是一道构造题(这是能说的吗
考虑如果要使得mex+1,那要复制的k肯定是mex,否则mex之前都没出现过,之后也不会出现过
那又分出了一些情况:
1.如果存在一些数=mex+2,是不是都要覆盖掉?否则就不是+1,可能+234了
那就从最左边的mex+2开始,一直赋值到最右边的mex+2
然后再重新算一遍当前mex是否满足条件(因为在覆盖过程中,可能会覆盖本来不应该覆盖的数)
2.假如没有的话,那只要挑>mex+2的数赋值为mex+1就好了
假如也没有>mex+2的数,那挑一个<mex的至少出现一次的赋值就好了
那要是也没有,则说明了当前是0,1,2,3,4...这种形式,必然有mex==n,特判一下就好。
#include<bits/stdc++.h> using namespace std; const int maxn=200005; int n,a[maxn]; map<int,int>cnt; bool solve(){ cnt.clear(); cin>>n; for(int i=1;i<=n;i++) cin>>a[i],cnt[a[i]]=1; int mex; for(int i=0;i<=min(n,200000);i++) if(!cnt[i]) { mex=i;break; } // part1: exit x that x==mex+1 bool flag1=false; //cout<<mex<<endl; for(int i=1;i<=n;i++) if(a[i]==mex+1) flag1=true; if(flag1){ int left=0,right=0; for(int i=1;i<=n;i++) if(a[i]==mex+1) { left=i;break;} for(int i=n;i>=1;i--) if(a[i]==mex+1) { right=i;break;} cnt.clear(); for(int i=1;i<left;i++) cnt[a[i]]=1; for(int i=right+1;i<=n;i++) cnt[a[i]]=1; cnt[mex]=1; int newmex; for(int i=0;i<=min(n,200000);i++) if(!cnt[i]) { newmex=i;break; } if(newmex==mex+1) return true; else return false; } bool flag2=false; for(int i=1;i<=n;i++) if(a[i]>=mex+2) flag2=true; if(flag2){ return true; } if(mex==n) return false; else return true; } int main(){ //freopen("lys.in","r",stdin); int t; cin>>t; while(t--){ if(solve()) cout<<"Yes"<<endl; else cout<<"No"<<endl; } }
D.发现小猫没说全题意时,我们已经卡了半小时了哈哈哈哈
趁着修猫上厕所突发奇想重新看了一遍题()
本来以为是纯拼图,后面发现每次其实是取当前的长和宽,这还是很不一样的
现场猜dfs+线段树维护最大值可做,并且答案肯定有一个数是x的最大值或者y的最大值
后面想想又觉得甚至不用dfs,每次的决策甚至可能只有一步,找个时间补一下~~