Codeforces Round #545 (Div. 2)
题目总链接:https://codeforces.com/contest/1138
A. Sushi for Two
题意:
给出n个数,只有1或者2,要求找出最长的连续的1,后面跟着相等长度的连续的2。问这个最长长度为多少。
题解:
模拟一下就行了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double lb; const int N = 2e5+5; int a[N]; int n; int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int b=0,c=0,d=0; int ans =0; if(a[1]==2) b++; else c++; if(a[n]==1) a[n+1]=2; else a[n+1]=1; for(int i=2;i<=n+1;i++){ if(a[i]==a[i-1]&&a[i]==2){ b++; }else if(a[i]==a[i-1]&&a[i]==1){ c++; }else{ if(a[i]==2){ ans=max(ans,2*min(c,b)); b=1; }else{ ans=max(ans,2*min(c,b)); c=1; } } } cout<<ans; return 0; }
B. Circus
题意:
有n个人,一共有两个表演,这n个人有些只会其中一个,有些人什么都不会,还有些人全都会。然后现在有两场表演,每场要选出n/2个人,最终要求两场表演中,会第一种才艺的人数和会第二种才艺的人数相等。注意这里n为偶数。
题解:
这个暴力真的秀,我说说思路吧,不要看我代码了,太丑了,而且复杂度也有点高,卡着时间过的。
思路就是枚举第一个表演中要选多少个两种都会的人以及只会第一种才艺的人,然后根据这两个把其余的算出来。比如两种都会的有all个人,只会第一种有fir个人,只会第二种有sec个人,什么都不会的有none个人,我们现在枚举了i和j,分别对应all和fir,那么我们就确定了第二场表演需要多少个会才艺的人,为i+j个人。但是可能还会选择一些人来凑够n/2个人,比如k就为第一场表演中应该选多少个sec中的人来凑数,那么k就应该满足all-i+sec-k=i+j,这样另外一种的人数也就可以确定了。
我的做法就是暴力枚举k的...最后需要注意一些边界情况的判断。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5005; vector <int> g[5]; int n; char s1[N],s2[N]; int main(){ scanf("%d",&n); scanf("%s%s",s1+1,s2+1); int all=0,fir=0,sec=0,no=0; for(int i=1;i<=n;i++){ if(s1[i]=='1'&&s2[i]=='1'){ g[0].push_back(i); all++; }else if(s1[i]=='1'){ g[1].push_back(i); fir++; }else if(s2[i]=='1'){ g[2].push_back(i); sec++; }else{ g[3].push_back(i); no++; } } for(int i=0;i<=all;i++){ for(int j=0;j<=fir;j++){ int need = i+j; if(need<=n/2&&all-i+sec>=need){ for(int k=0;k<=sec;k++){ if(need==sec-k+all-i&&n/2-need-k>=0){ int non=n/2-need-k; if(non>no) continue ; i--;j--;k--;non--; //cout<<i<<" "<<j<<" "<<k<<" "<<non<<endl; while(i>=0) printf("%d ",g[0][i]),i--; while(j>=0) printf("%d ",g[1][j]),j--; while(k>=0) printf("%d ",g[2][k]),k--; while(non>=0) printf("%d ",g[3][non]),non--; return 0; } } } } } printf("-1"); return 0; }、
C. Skyscrapers
题意:
给出n*m个数,每个位置都有相应的数值,然后对于每一个位置,输出将该行、列离散化后,最大的那个值,注意这里离散化是同时的,也就是数的大小关系要同时满足原先行、列中的大小关系。
题解:
做法就是对每一行、每一列进行离散化,同时维护每一行、每一列的最大值,然后对于每一个位置的数计算一下就好了。
具体计算方法见代码吧:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1005; int n,m; int mp[N][N]; int r[N][N],c[N][N]; int mx1[N],mx2[N]; struct node{ int v,id; bool operator <(const node&A){ return v<A.v; } }a[N]; int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>mp[i][j]; r[i][j]=c[i][j]=mp[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[j].v=mp[i][j];a[j].id=j; } sort(a+1,a+m+1); int cnt = 0; for(int j=1;j<=m;j++){ if(a[j].v==a[j-1].v) cnt++; r[i][a[j].id]=j-cnt; mx1[i]=max(mx1[i],j-cnt); } } /*for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<r[i][j]<<" "; } cout<<endl; }*/ for(int j=1;j<=m;j++){ for(int i=1;i<=n;i++){ a[i].v=mp[i][j];a[i].id=i; } sort(a+1,a+n+1); int cnt = 0; for(int i=1;i<=n;i++){ if(a[i].v==a[i-1].v) cnt++; c[a[i].id][j]=i-cnt; mx2[j]=max(mx2[j],i-cnt); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int mx=max(mx1[i],mx2[j]); int tmp1=r[i][j],tmp2=c[i][j]; int ans = 0; if(tmp1>tmp2){ ans=max(mx1[i],mx2[j]+tmp1-tmp2); }else if(tmp1<tmp2){ ans=max(mx2[j],mx1[i]+tmp2-tmp1); }else{ ans=max(mx1[i],mx2[j]); } //ans=max(mx1[i],mx2[j])+abs(tmp1-tmp2); cout<<ans<<" "; } cout<<' '; } return 0; }
D. Camp Schedule
题意:
给出一个s串,然后给出一个t串,其中只包含0或者1,然后对s串中数的顺序进行重排,要求t串出现的次数最多(可以重叠)。
题解:
求出t串的最小循环节然后直接构造就行了,求最小循环节就利用kmp算法,最后l-next[l]就是答案。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double lb; const ll N = 5e5+5; ll n; char s[N],t[N]; int f[N]; void Getfail(char *P){ memset(f,0,sizeof(f)); int l=strlen(P); for(int i=1;i<l;i++){ int j=f[i]; while(j && P[i]!=P[j]) j=f[j]; f[i+1]=P[j]==P[i] ? j+1 : 0; } } int main(){ scanf("%s",s); scanf("%s",t); Getfail(t); ll l1=strlen(s),l2=strlen(t); ll c1=0,c2=0; ll tmp=l2-f[l2]; t[tmp]='