AtCoder Grand Contest 029 翻车记
A:对于每个B,会和其右边的每个W交换一次。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 200010 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; ll ans=0; char s[N]; int main() { scanf("%s",s+1);n=strlen(s+1); int cnt=0; for (int i=n;i;i--) if (s[i]=='W') cnt++; else ans+=cnt; cout<<ans; return 0; }
B:从大到小贪心,遇到某个数能和其他数组成2的次幂就把他俩删掉。正确性基于这点:按从大到小的顺序找到的数,若能匹配,其在剩余的数中所能匹配的数是唯一的,这样匹配之后无论如何不会更劣。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; #define ll long long #define N 200010 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,a[N],ans; map<int,int> cnt; int main() { n=read(); for (int i=1;i<=n;i++) cnt[a[i]=read()]++; sort(a+1,a+n+1); for (int i=n;i>=1;i--) if (cnt[a[i]]) { int t=a[i];cnt[a[i]]--; while (t!=(t&-t)) t^=t&-t; if (cnt[(t<<1)-a[i]]) ans++,cnt[(t<<1)-a[i]]--; else cnt[a[i]]++; } cout<<ans; return 0; }
C:调了半天贪心一直过不掉,好长时间之后才发现假掉了,加个二分就过了,莫名其妙的花了50min。二分答案,维护一个栈存储字符串的非a位置,如果当前字符串比上个字符串长,显然后面全填上a就可以了;否则弹栈至非a位置不大于当前串长度,然后将末尾达到限制的位置弹出,如果弹空了说明不合法(当然如果有剩余的a是合法的),否则将未达限制的最后一位+1,后面全清成a即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 200010 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,a[N],pos[N],num[N],top,ans; bool check(int ans) { top=0; for (int i=2;i<=n;i++) if (a[i]<=a[i-1]) { int x=a[i]; while (top&&pos[top]>x) top--; while (top&&pos[top]==x&&num[top]==ans) top--,x--; if (x==0) return 0; else if (pos[top]<x) {pos[++top]=x,num[top]=2;if (ans==1) return 0;} else num[top]++; } return 1; } int main() { n=read(); for (int i=1;i<=n;i++) a[i]=read(); int l=1,r=n; while (l<=r) { int mid=l+r>>1; if (check(mid)) ans=mid,r=mid-1; else l=mid+1; } cout<<ans; return 0; }
D:显然第一个人每次都是必须走的。每进入某一列,第二个人都可以选择一直不动,直到第一个人的移动使其撞到障碍。如果可以到达(x,y),则对(x,1..y-1),要么可以到达,要么在x之前有障碍。那么让一颗棋子从起点出发,每次都尽量移动,set找一下该列最近障碍,对每一列的答案取个min即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> #include<set> using namespace std; #define ll long long #define N 200010 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 r,c,n,t,x,y,ans; map<int,int> f[N]; set<int> g[N]; struct data{int x,y; }a[N]; int main() { r=read(),c=read();n=read();ans=r+1; for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),f[a[i].x][a[i].y]=1,g[a[i].y].insert(a[i].x); for (int i=1;i<=c;i++) g[i].insert(r+1); int x=1,y=1; for (;x<r;) { ans=min(ans,*g[y].lower_bound(x)); x++;if (!f[x][y+1]&&y<c) y++; } ans=min(ans,*g[y].lower_bound(x)); cout<<ans-1; return 0; }
死于罚时。result:rank 110 rating +389