Codeforces Round #545 Div. 1自闭记
Posted gloid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #545 Div. 1自闭记相关的知识,希望对你有一定的参考价值。
A:求出该行该列各有多少个比其小的取max,该行该列各有多少个比其大的取max,加起来即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1010 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N][N],ans[N][N],ans2[N][N],b[N]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j]=read(); for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) b[j]=a[i][j]; sort(b+1,b+m+1); int t=unique(b+1,b+m+1)-b-1; for (int j=1;j<=m;j++) { int x=lower_bound(b+1,b+t+1,a[i][j])-b; ans[i][j]=max(ans[i][j],x); ans2[i][j]=max(ans2[i][j],t-x); } } for (int i=1;i<=m;i++) { for (int j=1;j<=n;j++) b[j]=a[j][i]; sort(b+1,b+n+1); int t=unique(b+1,b+n+1)-b-1; for (int j=1;j<=n;j++) { int x=lower_bound(b+1,b+t+1,a[j][i])-b; ans[j][i]=max(ans[j][i],x); ans2[j][i]=max(ans2[j][i],t-x); } } for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) printf("%d ",ans[i][j]+ans2[i][j]); printf(" "); } return 0; //NOTICE LONG LONG!!!!! }
B:kmp求出最长border,贪心的每次利用这个border制造新子串即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1000010 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,cnt,nxt[N],cnt2; char a[N],b[N]; signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif scanf("%s",a+1);n=strlen(a+1); scanf("%s",b+1);m=strlen(b+1); for (int i=1;i<=n;i++) if (a[i]==‘1‘) cnt++; for (int i=1;i<=m;i++) if (b[i]==‘1‘) cnt2++; nxt[0]=-1; for (int i=1;i<=m;i++) { int j=nxt[i-1]; while (b[j+1]!=b[i]&&j!=-1) j=nxt[j]; nxt[i]=j+1; } if (n<m) {printf("%s",a+1);return 0;} if (cnt<cnt2||n-cnt<m-cnt2) {printf("%s",a+1);return 0;} int X=cnt,Y=n-cnt; printf("%s",b+1);X-=cnt2,Y-=m-cnt2; cnt=0;for (int i=nxt[m]+1;i<=m;i++) if (b[i]==‘1‘) cnt++; cnt2=m-nxt[m]-cnt; while (X>=cnt&&Y>=cnt2) { for (int i=nxt[m]+1;i<=m;i++) putchar(b[i]); X-=cnt,Y-=cnt2; } for (int i=1;i<=X;i++) printf("1"); for (int i=1;i<=Y;i++) printf("0"); return 0; //NOTICE LONG LONG!!!!! }
C:场上写了1h假题意。终于看懂题之后又被之前假题意的做法带偏了。考虑拆点,建出新图后缩点,跑最长链即为答案。因为由图的特殊性容易发现,若新图中有两个点代表原图中同一个点的不同时刻且其弱联通,其一定处于同一SCC中。所以不会出现多次计算同一个点的贡献的情况。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; #define ll long long #define N 100010 #define M 54 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,d,p[N],dfn[N*M],low[N*M],stk[N*M],Set[N*M],P[N*M],nxt[N*M],top,cnt,t,ans,a[N][M]; bool flag[N*M]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} int id(int n,int m){return (n-1)*d+m;} void tarjan(int x,int y) { int k=id(x,y); dfn[k]=low[k]=++cnt; stk[++top]=k;flag[k]=1; for (int i=p[x];i;i=edge[i].nxt) if (!dfn[id(edge[i].to,y%d+1)]) tarjan(edge[i].to,y%d+1),low[k]=min(low[k],low[id(edge[i].to,y%d+1)]); else if (flag[id(edge[i].to,y%d+1)]) low[k]=min(low[k],dfn[id(edge[i].to,y%d+1)]); if (dfn[k]==low[k]) { t++; while (stk[top]!=k) { nxt[stk[top]]=P[t]; P[t]=stk[top]; flag[stk[top]]=0; Set[stk[top]]=t; top--; } flag[k]=0,Set[k]=t,top--; nxt[k]=P[t];P[t]=k; } } namespace DAG { int p[N*M],n,t,f[N*M],value[N*M]; struct data{int to,nxt;}edge[N*M]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dp() { for (int i=1;i<=n;i++) { for (int j=p[i];j;j=edge[j].nxt) f[i]=max(f[i],f[edge[j].to]); f[i]+=value[i]; } } } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(),d=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y); } for (int i=1;i<=n;i++) for (int j=1;j<=d;j++) { char c=getchar(); while (c!=‘0‘&&c!=‘1‘) c=getchar(); a[i][j]=c-‘0‘; } t=0; for (int i=1;i<=n;i++) for (int j=1;j<=d;j++) if (!dfn[id(i,j)]) tarjan(i,j); DAG::n=t; for (int i=1;i<=n;i++) for (int x=1;x<=d;x++) for (int j=p[i];j;j=edge[j].nxt) if (Set[id(i,x)]!=Set[id(edge[j].to,x%d+1)]) DAG::addedge(Set[id(i,x)],Set[id(edge[j].to,x%d+1)]); memset(flag,0,sizeof(flag)); for (int i=1;i<=t;i++) { for (int j=P[i];j;j=nxt[j]) if (!flag[(j-1)/d+1]&&a[(j-1)/d+1][(j-1)%d+1]) DAG::value[i]++,flag[(j-1)/d+1]=1; for (int j=P[i];j;j=nxt[j]) flag[(j-1)/d+1]=0; } DAG::dp(); cout<<DAG::f[Set[1]]; return 0; //NOTICE LONG LONG!!!!! }
D:看到这张图就容易想到floyd判环。于是先拉两个点出来跑一遍,大约能得到一个2(t+d)=t+d+kc。其中k和c都可以确定。这样大概可以二分一下t,但点数说不定不太够。事实上这个时候直接让所有点一起往前跑第一次撞上就是答案了。因为t+d=kc,当前环上点在d的位置,走t步后刚好走到终点。同时由起点出发的点也刚好走了t步到达终点。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } char s[12]; int main() { #ifndef ONLINE_JUDGE freopen("b.in","r",stdin); freopen("b.out","w",stdout); #endif int cnt=0; while (1) { cout<<"next 1 2"<<endl; int x=read(); for (int i=1;i<=x;i++) scanf("%s",s); cout<<"next 1"<<endl; x=read(); for (int i=1;i<=x;i++) scanf("%s",s); if (x==2) break; } while (1) { cout<<"next 0 1 2 3 4 5 6 7 8 9"<<endl; int x=read(); for (int i=1;i<=x;i++) scanf("%s",s); if (x==1) {cout<<"done"<<endl;return 0;} } }
剩下的先咕着。
感觉非常可怕的是看完sol不是感叹题好神而是感叹自己傻逼。
靠着偶尔快起来的切傻逼题的手速上了红,事实上还是打铁实力。简直自闭。
小号打的。result:rank 254 rating -19
以上是关于Codeforces Round #545 Div. 1自闭记的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #545 Div. 1自闭记
Codeforces Round #545 (Div. 2) 掉分记
Codeforces Round #545 (Div. 2)D(KMP,最长公共前后缀,贪心)
Codeforces Round #545 (Div. 2)A. Sushi for Two