A:签到。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 110 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],s,ans=0; int calc(int k){return abs(s-a[k]*n);} int main() { /*#ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif*/ n=read(); for (int i=1;i<=n;i++) s+=a[i]=read(); for (int i=2;i<=n;i++) if (calc(i)<calc(ans+1)) ans=i-1; cout<<ans; return 0; }
B:按位从高到低贪心,对当前位数一下有多少个子区间和该位为1,如果能满足要求就将其统计入答案并删掉所有该位为0的子区间和。
#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,b[N],cnt=0; ll a[N*N],c[N*N],ans; int main() { /*#ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif*/ n=read(),m=read(); for (int i=1;i<=n;i++) b[i]=read(); for (int i=1;i<=n;i++) { a[++cnt]=b[i]; for (int j=i+1;j<=n;j++) cnt++,a[cnt]=a[cnt-1]+b[j]; } n=cnt; for (int j=40;~j;j--) { int s=0; for (int i=1;i<=n;i++) if (a[i]&(1ll<<j)) c[++s]=a[i]; if (s>=m) { ans+=1ll<<j;n=s; for (int i=1;i<=s;i++) a[i]=c[i]; } } cout<<ans; return 0; }
C:指针从左到右扫一遍,两个队列分别维护指针左方D的出现位置和右方C的出现位置,并记录跨过当前位置的合法D~C区间有多少个。如果指针扫到M就更新答案,扫到D将其加入左边队列并统计以该位置为左端点的合法D~C区间数量,扫到C将其弹出右边队列并统计以该位置为右端点的合法D~C区间数量,拿两个指针记录两个队列中能产生贡献的边界位置即可做到线性。为啥atcoder不define ONLINE_JUDGE啊白交了一发。
#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,q,m,a[N],b[N],c[N]; char s[N]; int main() { n=read();scanf("%s",s+1); for (int i=1;i<=n;i++) if (s[i]=='D') a[i]=0; else if (s[i]=='M') a[i]=1; else if (s[i]=='C') a[i]=2; else a[i]=-1; q=read(); while (q--) { m=read(); int hb=1,tb=0,hc=1,t=0,tc=0;ll ans=0,cur=0; for (int i=1;i<=n;i++) if (a[i]==2) b[++tb]=i; for (int i=1;i<=n;i++) if (a[i]==1) ans+=cur; else if (a[i]==0) { c[++tc]=i; while (t<tb&&b[t+1]-i+1<=m) t++; cur+=t-hb+1; } else if (a[i]==2) { while (hc<=tc&&i-c[hc]+1>m) hc++; cur-=tc-hc+1; hb++; } cout<<ans<<endl; } return 0; }
D:可以发现每个点最终可以被移动到该剩余类的任意位置。那么数一下每个剩余类有多少个点。这些点最后应该排成a*(a-1)的长方形或a*a的正方形。可以枚举最终矩形左下角坐标并二分边长check一发,这样就能拿到部分分了。然后好像还不太会。
E:没看。
感觉atcoder赛制不是非常友好啊。result:rank 185 rating +352