Codeforces Round #650 (Div. 3)
打的 vp,花了 1h 30min 切了前 6 个,后来花了 20min 把最后一题也切掉了.
难度不大,但是想要进前 10 的话手速还是要快一点.
A - Short Substrings
观察一下字符串,然后发现相同的保留一个就行.
#include <bits/stdc++.h> #define N 1087 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; char str[N]; void solve() { scanf("%s",str+1); int n=strlen(str+1); printf("%c",str[1]); for(int i=2;i<=n-2;i+=2) { printf("%c",str[i]); } printf("%c\n",str[n]); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }
B - Even Array
判断合不合法很简单,然后最小步数显然就是偶数/奇数不合法的位置个数.
#include <bits/stdc++.h> #define N 1008 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int a[N],c0,c1,c2; void solve() { int n; scanf("%d",&n); c0=c1=c2=0; for(int i=0;i<n;++i) { scanf("%d",&a[i]); if(a[i]&1) ++c1; else ++c0; if((a[i]&1)!=(i&1)) { ++c2; } } if(c0!=(n+1)/2) printf("-1\n"); else printf("%d\n",c2/2); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }
C - Social Distance
可以用差分数组维护 0 的连通块.
连通块内贪心去填 1 就行,也就是 $\frac{len}{(k+1)}+(len \% (k+1) != 0)$
#include <bits/stdc++.h> #define N 200009 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; char str[N]; int a[N]; void solve() { int n,k; scanf("%d%d",&n,&k); scanf("%s",str+1); for(int i=1;i<=n+3;++i) a[i]=0; for(int i=1;i<=n;++i) { if(str[i]=='1') { a[max(1,i-k)]++; a[min(i+k,n)+1]--; } } int pre0=0,mx=0; for(int i=1;i<=n;++i) { a[i]+=a[i-1]; if(!a[i]) ++pre0; else { mx+=pre0/(k+1); if(pre0%(k+1)) ++mx; pre0=0; } } mx+=pre0/(k+1); if(pre0%(k+1)) ++mx; printf("%d\n",mx); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }
D - Task On The Board
从大到小依次考虑,显然最大的 b[i]=0,然后次大的 b[i]=该位置到所有最大的距离.
这样可以判断序列中元素的 rank,然后再贪心去填字母就行了.
#include <bits/stdc++.h> #define N 53 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; char str[N]; int n,m,a[N],RK[N],cnt[N],num[N],ou[N]; void solve() { memset(RK,0,sizeof(RK)); memset(cnt,0,sizeof(cnt)); memset(num,0,sizeof(num)); memset(ou,0,sizeof(ou)); scanf("%s",str+1); n=strlen(str+1); for(int i=1;i<=n;++i) ++num[str[i]-'a']; scanf("%d",&m); for(int i=1;i<=m;++i) scanf("%d",&a[i]); int bu=0; for(int i=1;;++i) { int flag=0; for(int j=1;j<=m;++j) { if(RK[j]) continue; int cur=0; for(int t=1;t<=m;++t) { if(RK[t]&&RK[t]<i) cur+=abs(t-j); } if(cur==a[j]) RK[j]=i,flag=1,++cnt[i]; } if(!flag) break; bu=i; } int c=1; for(int i=27;i>=0;--i) { if(num[i]>=cnt[c]) { ou[c]=i; ++c; } if(c>bu) break; } for(int i=1;i<=m;++i) { printf("%c",'a'+ou[RK[i]]); } printf("\n"); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }
E - Necklace Assembly
循环节为 $k$,意味着序列可以分成若干段,每段长度都为 k,且所有段相等.
由于每段长度固定,所以可以二分段数.
然后由于这里的循环节可能非常大,所以不妨分解 k 的因数,然后对每个因数求一下答案,最后取 max.
#include <bits/stdc++.h> #define N 2008 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int cnt[30],n,K; char S[N]; int check(int x,int cur) { int tmp=0; for(int i=0;i<27;++i) { tmp+=cnt[i]/x; } return tmp>=cur; } int cal(int p) { int l=1,r=n,ans=0; while(l<=r) { int mid=(l+r)>>1; if(check(mid,p)) ans=mid,l=mid+1; else r=mid-1; } return ans*p; } void solve() { memset(cnt,0,sizeof(cnt)); scanf("%d%d",&n,&K); scanf("%s",S+1); for(int i=1;i<=n;++i) ++cnt[S[i]-'a']; int ans=0; for(int i=1;i<=n;++i) { if(K%i==0) { ans=max(ans,cal(i)); } } printf("%d\n",ans); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }
F2 - Flying Sort (Hard Version)
不难发现留下的是值域连续的一段,然后将值域两端分别扔到前后.
那么问题就转化成求极长值域连续的段数长度.
所有数互不相同显然很好求.
对于出现数字相同的情况,不难发现构成一定是 零散 + 所有值严格取到 + 零散的形式.
即只有最小和最大值可以不都取完,中间的必须都取完.
这个直接用 DP 求就行.
要特判中间没有严格取到的情况.
#include <bits/stdc++.h> #define N 1000009 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int f[N],a[N],A[N],fst[N],lst[N],pos[N],num[N],Num[N]; void solve() { int n; scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); A[i]=a[i]; } sort(A+1,A+1+n); int m=unique(A+1,A+1+n)-A-1; for(int i=1;i<=n+233;++i) f[i]=pos[i]=fst[i]=lst[i]=num[i]=Num[i]=0; for(int i=1;i<=n;++i) a[i]=lower_bound(A+1,A+1+m,a[i])-A,++Num[a[i]]; for(int i=1;i<=n;++i) { if(!fst[a[i]]) fst[a[i]]=i; lst[a[i]]=i; } int mx=0; for(int i=1;i<=n;++i) { f[i]=1; if(fst[a[i]]==i) { if(lst[a[i]-1]<i) f[i]=max(f[i],f[lst[a[i]-1]]+1); f[i]=max(f[i],num[a[i]-1]+1); } else f[i]=max(f[i],f[pos[a[i]]]+1); ++num[a[i]]; pos[a[i]]=i; if(lst[a[i]]==i) mx=max(mx,f[i]+Num[a[i]+1]-num[a[i]+1]); mx=max(mx,num[a[i]]+Num[a[i]+1]-num[a[i]+1]); } printf("%d\n",n-mx); } int main() { // setIO("input"); int T; scanf("%d",&T); while(T--) solve(); return 0; }