2017-2018 ACM-ICPC, Central Europe Regional Contest (CERC 17)
A. Assignment Algorithm
按题意模拟即可。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 60, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n, m, lft, rgt; int empty[N]; char s[N][20]; int rk[10][2]; int main() { scanf("%d%d", &n, &m); lft = n * 4; rgt = n * 4; for(int i = 1; i <= n + 3; i ++){ empty[i] = 9; scanf("%s", s[i] + 1); for(int j = 1; j <= 11; j ++){ if(s[i][j] == '#'){ empty[i] --; if(j <= 5) lft --; else if(j >= 7) rgt --; } } } for(int ch = 0; ch < m; ch ++){ //printf("%d %d %d\n", ch, lft, rgt); int tmpe = 0, o = 0, dis = 100; if(ch == 13){ int go = 1; } if(empty[2]){ tmpe = empty[2]; o = 2; } if(empty[n / 2 + 3] > tmpe){ tmpe = empty[n / 2 + 3]; o = n / 2 + 3; } if(o == 0){ for(int i = 3; i <= n / 2 + 1; i ++){ if(empty[i] > tmpe){ tmpe = empty[i]; o = i; dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2))); } else if(empty[i] == tmpe){ int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2))); if(tmpdis < dis){ dis = tmpdis; o = i; } } } for(int i = n / 2 + 4; i <= n + 2; i ++){ if(empty[i] > tmpe){ tmpe = empty[i]; o = i; dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2))); } else if(empty[i] == tmpe){ int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2))); if(tmpdis < dis){ dis = tmpdis; o = i; } } } } empty[o] --; rk[0][0] = 5, rk[0][1] = 7; rk[1][0] = 3, rk[1][1] = 9; rk[2][0] = 1, rk[2][1] = 11; rk[3][0] = 6, rk[3][1] = 6; rk[4][0] = 2, rk[4][1] = 10; for(int i = 0; i <= 4; i ++){ if(s[o][rk[i][0]] == '-' || s[o][rk[i][1]] == '-'){ if(i == 3){ s[o][6] = ch + 'a'; break; } if(s[o][rk[i][0]] == '-' && s[o][rk[i][1]] == '-'){ if(lft >= rgt) s[o][rk[i][0]] = ch + 'a', lft --; else s[o][rk[i][1]] = ch + 'a', rgt --; } else if(s[o][rk[i][0]] == '-'){ s[o][rk[i][0]] = ch + 'a', lft --; } else {s[o][rk[i][1]] = ch + 'a', rgt --;} break; } } } for(int i = 1; i <= n + 3; i ++){ printf("%s\n", s[i] + 1); } return 0; } /* 2 17 ........... ---.#--.--- ........... ---.---.--- ........... 6 26 ........... ---.---.### #-#.---.--- ---.###.--- ........... ---.###.--- #--.#-#.--# #--.--#.#-# ........... 0 17 12 1 16 12 2 15 12 3 15 11 4 15 10 5 14 10 6 13 10 7 12 10 8 12 9 9 12 9 10 11 9 11 10 9 12 10 8 13 9 8 14 8 8 15 8 7 16 8 6 17 7 6 18 7 5 19 6 5 20 5 5 21 4 5 22 4 4 23 4 3 24 4 2 25 4 2 ........... gke.aic.### #-#.mzo.r-v t-n.###.p-x ........... fjb.###.dlh #-s.#-#.w-# #-u.qy#.#-# ........... */ /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
B. Buffalo Barricades
首先通过扫描线求出最终的图中每个点属于哪个区域,以及包含每个区域的最小区域。
然后倒着处理每个询问,依次删掉每个栅栏,也就是将区域的点数合并,并查集维护。
时间复杂度$O((n+m)\log(n+m))$。
#include<cstdio> #include<algorithm> #include<set> using namespace std; typedef pair<int,int>P; const int N=600010; int n,m,ce,i,x,y,z,v[N],f[N],g[N],ans[N];set<P>T; struct E{int x,y,t;E(){}E(int _x,int _y,int _t){x=_x,y=_y,t=_t;}}e[N]; inline bool cmp(const E&a,const E&b){ if(a.y!=b.y)return a.y>b.y; return a.x<b.x; } inline int F(int x){return f[x]==x?x:f[x]=F(f[x]);} inline void merge(int x,int y){ x=F(x),y=F(y); if(x==y)return; f[x]=y,v[y]+=v[x]; } int main(){ scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d%d",&x,&y); x<<=1,y<<=1; e[++ce]=E(x,y,0); } scanf("%d",&m); for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); x<<=1,y<<=1; x++,y++; e[++ce]=E(x,y,i); f[i]=i; } sort(e+1,e+ce+1,cmp); for(i=1;i<=ce;i++){ x=e[i].x,z=e[i].t; if(z){ T.insert(P(x,z)); set<P>::iterator it=T.find(P(x,z)),k=it; k++; if(k!=T.end())g[z]=k->second; while(1){ k=T.find(P(x,z)); if(k==T.begin())break; k--; if(k->second<z)break; T.erase(k); } }else{ set<P>::iterator it=T.lower_bound(P(x,0)); if(it!=T.end())v[it->second]++; } } for(i=m;i;i--){ ans[i]=v[F(i)]; if(g[i])merge(i,g[i]); } for(i=1;i<=m;i++)printf("%d\n",ans[i]); }
C. Cumulative Code
留坑。
D. Donut Drone
LCT维护环套树,在根与根的父亲处断开。
对于link操作,若成环则无视。
对于cut操作,删边之后再将环边link即可。
对于查询操作,首先求出与环末端点的LCA,这就是进入环的点,剩下的部分模环长后分两段走即可。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=2010,M=N*N; int n,m,a[M],f[M],son[M][2],size[M]; int v[N][N],id[N][N],tot,loc[M][2],O; int i,j,k,x,y,z;char op[100]; inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;} inline void up(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;} inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x; else if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y); } inline void splay(int x){ while(!isroot(x)){ int y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } inline int access(int x){ int y=0; for(;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x); return y; } inline int lca(int x,int y){ access(x); return access(y); } inline int root(int x){ access(x); splay(x); while(son[x][0])x=son[x][0]; splay(x); return x; } inline void link(int x,int y){ if(root(x)!=root(y))splay(x),f[x]=y,access(x); } inline void cut(int x,int y){ int u=root(x); if(u==x)return; access(x); splay(x); f[son[x][0]]=0; son[x][0]=0; up(x); link(u,a[u]); } inline int dis(int x){ access(x); splay(x); return size[son[x][0]]; } inline int goup(int x,int k){ k=dis(x)-k+1; access(x); splay(x); while(1){ int t=size[son[x][0]]+1; if(k==t)return x; if(k<t)x=son[x][0];else k-=t,x=son[x][1]; } } inline int moveup(int x,int k){ x=goup(x,k); splay(x); return x; } inline int simulate(int x,int k){ int u=root(x),y=a[u],z=lca(x,y); int A=dis(x),B=dis(y),C=dis(z); if(A>C){ int t=min(A-C,k); k-=t; x=moveup(x,t); } k%=B+1; if(!k)return x; int t=min(dis(x),k); k-=t; x=moveup(x,t); if(!k)return x; x=y; k--; if(!k)return x; return moveup(x,k); } inline int getnxt(int o){ int x=loc[o][0],y=loc[o][1]; y++; y%=m; int mx=-1,w=0; for(int i=x-1;i<=x+1;i++){ int nx=(i%n+n)%n; if(v[nx][y]>mx){ mx=v[nx][y]; w=id[nx][y]; } } return w; } inline void check(int x,int y){ x%=n,y%=m; x+=n,y+=m; x%=n,y%=m; int o=id[x][y]; int now=getnxt(o); if(a[o]!=now){ cut(o,a[o]); a[o]=now; link(o,a[o]); } } int main(){ scanf("%d%d",&n,&m); for(i=0;i<n;i++)for(j=0;j<m;j++){ scanf("%d",&v[i][j]); id[i][j]=++tot; loc[tot][0]=i; loc[tot][1]=j; } for(i=1;i<=tot;i++)size[i]=1; for(i=1;i<=tot;i++){ a[i]=getnxt(i); link(i,a[i]); } O=id[0][0]; int _; scanf("%d",&_); while(_--){ scanf("%s",op); if(op[0]=='c'){ scanf("%d%d%d",&x,&y,&z); x--,y--; v[x][y]=z; check(x-1,y-1); check(x,y-1); check(x+1,y-1); }else{ scanf("%d",&k); O=simulate(O,k); printf("%d %d\n",loc[O][0]+1,loc[O][1]+1); } } } /* 3 4 10 20 30 40 50 60 70 80 90 93 95 99 3 move 4 change 2 1 100 move 4 */
E. Embedding Enumeration
留坑。
F. Faulty Factorial
显然要修改的数与$n$相差不超过$P$,枚举每个数分类讨论即可。
#include<cstdio> #include<cstdlib> using namespace std; typedef long long ll; const int N=10000010; ll n; int P,R,i; int s[N],inv[N]; inline ll po(ll a,ll b,ll P){ ll t=1; for(;b;b>>=1,a=a*a%P)if(b&1)t=t*a%P; return t; } struct Num{ ll a,b; Num(){a=1,b=0;} Num(ll _a,ll _b){a=_a,b=_b;} Num operator*(Num x){return Num(a*x.a%P,b+x.b);} Num operator/(Num x){return Num(a*inv[x.a]%P,b-x.b);} }res; Num cal(ll n){ return n?Num(s[n%P]*po(s[P],n/P,P)%P,n/P)*cal(n/P):Num(1,0); } inline Num ask(ll n){ ll b=0; while(n%P==0)n/=P,b++; return Num(n%P,b); } void ok(ll a,ll b){ printf("%lld %lld",a,b); exit(0); } int main(){ scanf("%lld%d%d",&n,&P,&R); for(i=s[0]=1;i<P;i++)s[i]=1LL*s[i-1]*i%P; s[P]=s[P-1]; for(inv[0]=inv[1]=1,i=2;i<P;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P; res=cal(n); ll W=1LL*R*inv[res.a]%P; for(ll x=n;x>1&&x>n-P-10;x--){ ll A=x,B=0; while(A%P==0)A/=P,B++; if(res.b>B){ if(R)continue; ok(x,1); }else{ if(R){ ll y=A%P*W%P; if(y<x)ok(x,y); }else{ if(P<x)ok(x,P); } } } puts("-1 -1"); }
G. Gambling Guide
设$e_x$表示$x$到$n$的最优期望次数,则$e_n=0,e_x=\frac{\sum\min(e_x,e_y)}{deg_x}+1$。
每次用堆取出$e_x$最小的$x$,更新周围一圈点即可。
时间复杂度$O(m\log m)$。
#include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef pair<double,int>P; const int N=300010; const double inf=1e100; int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed; double f[N],s[N]; int d[N],c[N]; bool vis[N]; priority_queue<P,vector<P>,greater<P> >q; inline void add(int x,int y){ v[++ed]=y;nxt[ed]=g[x];g[x]=ed; d[x]++; } inline void ext(int x){ double now=(s[x]+d[x])/c[x]; if(now<f[x]){ f[x]=now; q.push(P(now,x)); } } inline void up(int x,double y){ vis[x]=1; for(int i=g[x];i;i=nxt[i]){ int u=v[i]; if(vis[u])continue; c[u]++; s[u]+=y; ext(u); } } int main(){ scanf("%d%d",&n,&m); while(m--){ scanf("%d%d",&x,&y); add(x,y); add(y,x); } for(i=1;i<n;i++)f[i]=inf; q.push(P(0,n)); while(!q.empty()){ P t=q.top();q.pop(); if(vis[t.second])continue; up(t.second,t.first); } printf("%.10f",f[1]); }
H. Hidden Hierarchy
按题意模拟即可。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int L = 1e5 + 10, N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int T; char s[L]; map<string, set<string> >mop; map<string, int>v; void dfs1(string x) { for(auto y : mop[x]) { dfs1(y); v[x] += v[y]; } } void dfs2(string x) { if(!mop[x].size()) { printf("%c %s %d\n", ' ', x.c_str(), v[x]); return; } bool flag = 0; for(auto y : mop[x]) { if(v[y] >= T)flag = 1; } if(!flag) { printf("%c %s %d\n", '+', x.c_str(), v[x]); return; } else { printf("%c %s %d\n", '-', x.c_str(), v[x]); for(auto y : mop[x]) { dfs2(y); } } } int main() { int n; while(~scanf("%d", &n)) { mop.clear();v.clear(); for(int i = 1; i <= n; ++i) { int val; scanf("%s%d", s, &val); string fa = "#"; for(int i = 0; s[i]; ++i)if(s[i] == '/') { char tmp = s[i + 1]; s[i + 1] = 0; mop[fa].insert(s); fa = s; s[i + 1] = tmp; } v[fa] += val; } string rt = "/"; dfs1(rt); // //printf("%d\n", v[rt]); // scanf("%d", &T); dfs2(rt); } return 0; } /* 【trick&&吐槽】 2 /a/a/a 100 /b.txt 99 200 【题意】 【分析】 【时间复杂度&&优化】 */
I. Intrinsic Interval
若一个区间$[l,r]$满足$max-min=r-l$,则值域连续。
也就是$max-min-r+l=0$,注意到$max-min-r+l\geq 0$恒成立,故为了在合法的情况下区间长度最短,应该满足$v=(max-min-r+l)n+r-l$最小,区间长度即为$v\bmod n$。
利用单调栈求出每个数作为最值的范围,对应$v$的矩形加。
从左往右考虑每个$l$,用线段树维护每个$r$的$v$,对于一个询问,答案即为区间历史最小值,线段树维护即可。
时间复杂度$O((n+m)\log n)$。
#include<cstdio> #include<algorithm> #define lc x<<1 #define rc x<<1|1 using namespace std; typedef long long ll; typedef pair<int,int>P; const int N=100010,M=262150,E=500010; const ll inf=1LL<<60; int n,Q,i,j,a[N],t,q[N],l[N],r[N]; int ga[N],gd[N],gq[N],ed,vl[E],vr[E],nxt[E];ll w[E]; P ans[N]; ll m[M],hm[M],d[M],hd[M]; ll fin; int pos; inline void Min(ll&a,ll b){a>b?(a=b):0;} inline void hdoa(int x,ll v){ Min(hm[x],m[x]+v); Min(hd[x],d[x]+v); } inline void doa(int x,ll v){ Min(hm[x],m[x]+=v); Min(hd[x],d[x]+=v); } inline void pb(int x){ if(hd[x])hdoa(lc,hd[x]),hdoa(rc,hd[x]),hd[x]=0; if(d[x])doa(lc,d[x]),doa(rc,d[x]),d[x]=0; } inline void up(int x){ m[x]=min(m[lc],m[rc]); Min(hm[x],min(hm[lc],hm[rc])); } void build(int x,int a,int b){ if(a==b){ hm[x]=m[x]=-1LL*a*(n-1); return; } int mid=(a+b)>>1; build(x<<1,a,mid); build(x<<1|1,mid+1,b); up(x); } void dfs(int x,int a,int b){ if(a==b){ hm[x]=m[x]; return; } pb(x); int mid=(a+b)>>1; dfs(x<<1,a,mid); dfs(x<<1|1,mid+1,b); m[x]=min(m[lc],m[rc]); hm[x]=min(hm[lc],hm[rc]); } void add(int x,int f,int t,int qf,int qt,ll v){ if(qf<=f&&t<=qt){doa(x,v);return;} pb(x); int mid=(f+t)>>1; if(qf<=mid)add(lc,f,mid,qf,qt,v); if(qt>mid)add(rc,mid+1,t,qf,qt,v); up(x); } inline void addedge(int&x,int l,int r,ll z){ vl[++ed]=l; vr[ed]=r; w[ed]=z; nxt[ed]=x; x=ed; } inline void ext(int xl,int xr,int yl,int yr,ll w){ //printf("%d %d %d %d %lld\n",xl,xr,yl,yr,w); if(w>=0){ addedge(ga[xl],yl,yr,w); addedge(gd[xr+1],yl,yr,-w); }else{ addedge(gd[xl],yl,yr,w); addedge(ga[xr+1],yl,yr,-w); } } void ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d){ Min(fin,hm[x]); return; } pb(x); int mid=(a+b)>>1; if(c<=mid)ask(x<<1,a,mid,c,d); if(d>mid)ask(x<<1|1,mid+1,b,c,d); } void getpos(int x,int a,int b,int c,int d){ if(pos)return; if(hm[x]>fin)return; if(a==b){ pos=a; return; } pb(x); int mid=(a+b)>>1; if(c<=mid)getpos(x<<1,a,mid,c,d); if(d>mid)getpos(x<<1|1,mid+1,b,c,d); } inline P query(int l,int r){ fin=inf; ask(1,1,n,r,n); //printf("! %d %d %lld\n",l,r,fin); pos=0; getpos(1,1,n,r,n); return P(pos-fin%n,pos); } int main(){ //(ma-mi-r+l)*n+r-l //ma*n-mi*n-r*(n-1)+l*(n-1) scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&a[i]); scanf("%d",&Q); for(i=1;i<=Q;i++){ int x,y; scanf("%d%d",&x,&y); addedge(gq[x],i,y,0); } for(q[t=0]=0,i=1;i<=n;i++){ while(t&&a[i]>a[q[t]])t--; l[i]=q[t]+1; q[++t]=i; } for(q[t=0]=n+1,i=n;i;i--){ while(t&&a[i]>a[q[t]])t--; r[i]=q[t]-1; q[++t]=i; } for(i=1;i<=n;i++)ext(l[i],i,i,r[i],1LL*a[i]*n); for(q[t=0]=0,i=1;i<=n;i++){ while(t&&a[i]<a[q[t]])t--; l[i]=q[t]+1; q[++t]=i; } for(q[t=0]=n+1,i=n;i;i--){ while(t&&a[i]<a[q[t]])t--; r[i]=q[t]-1; q[++t]=i; } for(i=1;i<=n;i++)ext(l[i],i,i,r[i],-1LL*a[i]*n); build(1,1,n); for(i=1;i<=n;i++){ add(1,1,n,1,n,n-1); for(j=ga[i];j;j=nxt[j]){ add(1,1,n,vl[j],vr[j],w[j]); } for(j=gd[i];j;j=nxt[j]){ add(1,1,n,vl[j],vr[j],w[j]); } if(i==1)dfs(1,1,n); for(j=gq[i];j;j=nxt[j]){ ans[vl[j]]=query(i,vr[j]); } } for(i=1;i<=Q;i++)printf("%d %d\n",ans[i].first,ans[i].second); } /* 7 3 1 7 5 6 4 2 3 3 6 7 7 1 3 7 3 1 7 5 6 4 2 3 3 6 7 7 1 3 1 1 1 2 21 2 2 2 2 7 1 3 3 7 49 4 4 4 4 35 4 5 5 7 42 6 6 6 7 28 7 7 7 7 14 1 1 1 1 -21 1 2 2 7 -7 3 3 3 3 -49 3 4 4 5 -35 5 5 5 5 -42 3 6 6 6 -28 3 7 7 7 -14 ! 1 3 -12 ! 3 6 -30 ! 7 7 -36 8 6 8 7 8 3 */
J. Justified Jungle
枚举每个$k$,那么剩下每个子树大小均为$\frac{n}{k+1}$,因此$k+1$一定是$n$的因子,若此时还满足子树大小为它的倍数的点数够$k+1$个,则可行。
#include<cstdio> const int N=1000010; int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed; int size[N]; int cnt[N]; inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x,int y){ size[x]=1; for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),size[x]+=size[v[i]]; cnt[size[x]]++; } inline bool check(int x){ x++; if(n%x)return 0; int w=n/x,t=0; for(int i=w;i<=n;i+=w)t+=cnt[i]; return t==x; } int main(){ scanf("%d",&n); for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x); dfs(1,0); for(i=1;i<n;i++)if(check(i))printf("%d ",i); }
K. Kitchen Knobs
因为$7$的因子只有$1$和$7$,因此最大值要么有$1$种,要么有$7$种,$7$种的显然无论怎么操作都是最优的,可以直接删掉。
问题转化为:给定$n$个数$a_1,a_2,...,a_n$,每次可以选择一个区间加上一个数,用最少的操作次数让所有数模$7$都为$0$。
将$a$差分,区间加操作也差分,则问题转化为:每次可以选择两个数,一个加上$k$,另一个减去$k$,用最少的操作次数让所有数模$7$都为$0$。
首先无视$0$,那么一定是先$1,6$配对、$2,5$配对、$3,4$配对,如此处理后最多还有$3$种数字$A,B,C$,问题转化为将这些数分成最多的组数,使得每组和都为$0$,记录$3$个数每个的个数然后DP即可。
#include<cstdio> #include<string> #include<algorithm> #include<iostream> using namespace std; const int N=505,inf=10000; int _,n,a[N],A,B,C,i,j,k,x,y,z,cnt[7],ans,m,e[N][4];short f[N][N][N],t; inline void up(short&a,short b){a>b?(a=b):0;} int ask(){ static char s[20]; scanf("%s",s); string best=""; for(int i=0;i<7;i++)best.push_back(s[i]); int mask=1; int sum=0; for(int i=1;i<7;i++){ string now=""; for(int j=0;j<7;j++){ now.push_back(s[(i+j)%7]); } if(now==best){ mask|=1<<i; sum+=i; }else if(now>best){ mask=1<<i; sum=i; best=now; } } if(mask!=(mask&(-mask)))return -1; return sum; } int main(){ scanf("%d",&_); while(_--){ int x=ask(); if(x<0)continue; a[++n]=x; } if(!n)return puts("0"),0; for(i=n+1;i;i--)a[i]-=a[i-1]; for(i=1;i<=n+1;i++)a[i]=((a[i]%7+7)%7); for(i=1;i<=n+1;i++)cnt[a[i]]++; while(cnt[1]&&cnt[6])cnt[1]--,cnt[6]--,ans++; A=cnt[1]?cnt[1]:cnt[6]; x=cnt[1]?1:6; while(cnt[2]&&cnt[5])cnt[2]--,cnt[5]--,ans++; B=cnt[2]?cnt[2]:cnt[5]; y=cnt[2]?2:5; while(cnt[3]&&cnt[4])cnt[3]--,cnt[4]--,ans++; C=cnt[3]?cnt[3]:cnt[4]; z=cnt[3]?3:4; for(i=0;i<=7;i++)for(j=0;j<=7;j++)for(k=0;k<=7;k++)if(i+j+k&&(i*x+j*y+k*z)%7==0){ e[m][0]=i; e[m][1]=j; e[m][2]=k; e[m++][3]=i+j+k-1; } for(i=0;i<=A;i++)for(j=0;j<=B;j++)for(k=0;k<=C;k++)if(i+j+k){ t=inf; for(x=0;x<m;x++)if(i>=e[x][0]&&j>=e[x][1]&&k>=e[x][2])up(t,f[i-e[x][0]][j-e[x][1]][k-e[x][2]]+e[x][3]); f[i][j][k]=t; } printf("%d",ans+f[A][B][C]); }
L. Lunar Landscape
利用二维前缀和标记出所有被覆盖的位置即可。
#include<cstdio> const int K=2005,N=4100; int n,x,y,d,i,j,k,a[N][N],b[N][N],f[N][N],ans;char op[9]; int main(){ scanf("%d",&n); while(n--){ scanf("%s%d%d%d",op,&x,&y,&d); x+=K,y+=K; if(op[0]=='A'){ x-=d/2,y-=d/2; a[x][y]++; a[x+d][y]--; a[x][y+d]--; a[x+d][y+d]++; }else{ d/=2; b[x][y-d]++; b[x-d][y]--; b[x+d][y]--; b[x][y+d]++; } } for(i=1;i<N;i++)for(j=1;j<N;j++){ a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1]; if(a[i][j])f[i][j]|=15; } for(j=1;j<N;j++)for(i=1;i<N;i++){ b[i][j]+=b[i-1][j-1]+b[i+1][j-1]; if(j>=2)b[i][j]-=b[i][j-2]; if(b[i][j]){ f[i][j]|=12; f[i][j+1]|=9; f[i-1][j]|=6; f[i-1][j+1]|=3; } } for(i=1;i<N;i++)for(j=1;j<N;j++)for(k=0;k<4;k++)if(f[i][j]>>k&1)ans++; printf("%.2f",0.25*ans); }