2017 国庆湖南 Day3
期望得分:100+30+60=190
实际得分:10+0+55=65
到了233 2是奇数位 或223 第2个2是偶数位就会223 、233 循环
#include<cstdio> #define N 1000001 using namespace std; char s[N+5]; int main() { freopen("trans.in","r",stdin); freopen("trans.out","w",stdout); int n,k; bool ok; while(scanf("%d%d",&n,&k)!=EOF) { scanf("%s",s+1); ok=false; for(int i=1;i<n;i++) { if(s[i]=='2' && s[i+1]=='3') { k--; if(s[i-1]=='2') { if(i&1) s[i+1]='2'; else { for(int j=1;j<i;j++) printf("%c",s[j]); if(k&1) printf("2"); else printf("3"); for(int j=i+1;j<=n;j++) printf("%c",s[j]); ok=true; break; } } else if(s[i+2]=='3') { if(i&1) { for(int j=1;j<=i;j++) printf("%c",s[j]); if(k&1) printf("3"); else printf("2"); for(int j=i+2;j<=n;j++) printf("%c",s[j]); ok=true; break; } else s[i]='3'; } else { if(i&1) s[i+1]='2'; else s[i]='3'; } if(!k) break; } } if(!ok) for(int i=1;i<=n;i++) printf("%c",s[i]); printf("\n"); } return 0; }
注:不能向上走
因为蛇可以在一行内任意移动
他最终在一行内的移动范围是一段连续的区间
所以本题可以用区间DP解决
f[i][j][k] 表示 前i行,长度为j,从第k列离开第i行的最大得分
g[j][l][r] 表示当前长度为j,在区间[l,r]内移动,没有死亡的最大得分
开始时 ,对于每一个i,f[i][j][k]=g[j][k][k]=f[i-1][g-a[i][k]][k]+max(-a[i][k],0)
然后,区间由内向外更新, g[j][l][r]=max(g[j-a[i][l]][l+1][r]+a[i][l],g[j-a[i][r]][l][r-1]+a[i][r])
最后 更新f f[i][j][k]=max(g[j][l][r]) k∈[l,r]
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 201 using namespace std; int a[N][6]; int f[N][N*10][6],g[N*10][6][6]; bool can[N][6]; void read(int &x) { x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f; } int main() { freopen("snakevsblock.in","r",stdin); freopen("snakevsblock.out","w",stdout); int n,sum=4; read(n); for(int i=1;i<=n;i++) for(int j=1;j<=5;j++) { read(a[i][j]); if(a[i][j]>0) sum+=a[i][j]; } int m,x,y; read(m); for(int i=1;i<=m;i++) { read(x); read(y); can[x][y]=true; } memset(f,-127,sizeof(f)); f[0][4][3]=0; int r; for(int i=1;i<=n;i++) { memset(g,-127,sizeof(g)); for(int j=0;j<=sum;j++) for(int k=1;k<=5;k++) if(j-a[i][k]>=0) f[i][j][k]=g[j][k][k]=f[i-1][j-a[i][k]][k]+max(-a[i][k],0); for(int len=2;len<=5;len++) for(int l=1;l+len-1<=5;l++) for(int j=0;j<=sum;j++) { r=l+len-1; if(!can[i][l] && j-a[i][l]>=0) g[j][l][r]=g[j-a[i][l]][l+1][r]+max(-a[i][l],0); if(!can[i][r-1] && j-a[i][r]>=0) g[j][l][r]=max(g[j][l][r],g[j-a[i][r]][l][r-1]+max(-a[i][r],0)); for(int k=l;k<=r;k++) f[i][j][k]=max(f[i][j][k],g[j][l][r]); } } int ans=0; for(int i=1;i<=n;i++) for(int j=0;j<=sum;j++) for(int k=1;k<=5;k++) ans=max(ans,f[i][j][k]); printf("%d",ans); }
前 30%: O(2^n * n^3)
暴力枚举哪些站点损坏,floyd判断这些站点损坏时,测试的站点是否连通
另20%:O(nlogn+k)
问题转化为选择最少的点覆盖所有的线段
即留下最多的区间,使区间不相交
按右端点从小到大排序 ,删掉与当前区间有交的区间
另10%:分类讨论即可
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 100001 int n,m,k,out=1e6; int front[N],nxt[N<<1],to[N<<1],tot; int in[N],ans[N],id[N],cnt; int cut[N][2]; bool con[16][16],f[16]; int E[N][2]; int vis[N],fa[N][18]; struct node { int l,r,nl,nr; }e[N*3]; queue<int>q; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } bool cmp(node p,node q) { return p.nr<q.nr; } void bfs(int x) { id[x]=++cnt; q.push(x); int now; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) if(!id[to[i]]) id[to[i]]=++cnt,q.push(to[i]); } } void solve2(int start) { bfs(start); read(k); for(int i=1;i<=k;i++) { read(e[i].l),read(e[i].r); e[i].nl=id[e[i].l]; e[i].nr=id[e[i].r]; if(e[i].nl>e[i].nr) swap(e[i].l,e[i].r),swap(e[i].nl,e[i].nr); } sort(e+1,e+k+1,cmp); int sum=0,last=0; for(int i=1;i<=k;i++) if(e[i].nl>last) last=e[i].nr,ans[++sum]=e[i].r; printf("%d\n",sum); for(int i=1;i<=sum;i++) printf("%d ",ans[i]); } void judge(int sum) { memset(con,false,sizeof(con)); for(int i=1;i<=n;i++) if(!f[i]) con[i][i]=true; for(int i=1;i<=m;i++) if(!f[E[i][0]] && !f[E[i][1]]) con[E[i][0]][E[i][1]]=con[E[i][1]][E[i][0]]=true; for(int h=1;h<=n;h++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(h!=i && h!=j && i!=j && con[i][h] && con[h][j]) con[i][j]=true; for(int i=1;i<=k;i++) if(con[cut[i][0]][cut[i][1]]) return; if(sum<out) { out=sum; for(int i=1,j=1;i<=n;i++) if(f[i]) ans[j++]=i; } } void dfs(int now,int sum) { if(sum>=out) return; if(now==n+1) { judge(sum); return; } dfs(now+1,sum); f[now]=true; dfs(now+1,sum+1); f[now]=false; } void solve1() { read(k); for(int i=1;i<=k;i++) read(cut[i][0]),read(cut[i][1]); dfs(1,0); printf("%d\n",out); for(int i=1;i<=out;i++) printf("%d ",ans[i]); } void dfs2(int x,int y) { id[x]=++tot; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) fa[to[i]][0]=x,dfs2(to[i],x); } int getlca(int u,int v) { if(u==v) return u; if(id[u]<id[v]) swap(u,v); for(int i=17;i>=0;i--) if(id[fa[u][i]]>id[v]) u=fa[u][i]; return fa[u][0]; } void solve3() { tot=0; dfs2(1,0); for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; read(k); int u,v,lca; for(int i=0;i<k;i++) { read(u); read(v); lca=getlca(u,v); vis[u]|=1<<i; for(int j=fa[u][0];j!=lca;j=fa[j][0]) vis[j]|=1<<i; vis[v]|=1<<i; for(int j=fa[v][0];j!=lca;j=fa[j][0]) vis[j]|=1<<i; vis[lca]|=1<<i; } tot=(1<<k)-1; for(int i=1;i<=n;i++) if(vis[i]==tot) { printf("1\n%d",i); return; } int s,g; int t1,t2,t3; if(k==3) { bool ok=true;; for(int i=1;i<=n;i++) { s=vis[i]; g=0; while(s) g+=(s&1),s/=2; if(g!=1) { ok=false; break; } if(vis[i]==1) t1=i; else if(vis[i]==2) t2=i; else t3=i; } if(ok) { printf("3\n%d %d %d",t1,t2,t3); return; } else { int d[8]; memset(d,0,sizeof(d)); for(int i=1;i<=n;i++) { d[vis[i]]=i; if(d[tot^vis[i]]) { printf("2\n%d %d",i,d[tot^vis[i]]); return; } } } } int r1=0,r2=0,p1; for(int i=1;i<=n;i++) if(vis[i]!=r1 || vis[i]!=r2) { if(vis[i]!=r1) r1=vis[i],p1=i; else { printf("2\n%d %d",p1,i); return; } } } void init() { read(n); read(m); int u,v; for(int i=1;i<=m;i++) { read(u); read(v); add(u,v); in[u]++; in[v]++; E[i][0]=u; E[i][1]=v; } int sum=0,fir; for(int i=1;i<=n;i++) if(in[i]!=2) sum++,fir=i; if(sum==2) solve2(fir); else if(n<=15) solve1(); else if(k<=3) solve3(); } int main() { freopen("ping11.in","r",stdin); // freopen("ping.out","w",stdout); init(); }
满分做法:
将链上的做法搬到树上
对所有的询问,按他们的lca排序
然后从下到上处理树上的节点,若以当前节点为lca的测试站点还连通,就把当前节点破坏
dfs序+树链剖分维护即可
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 int n,m,p; int cut[N*3][2],lca[N*3]; int siz[N],fa[N][18]; int cnt,id[N],bl[N]; int q[N*3],lr[N][2]; bool f[N<<2]; int ans[N]; int front[N],nxt[N<<1],to[N<<1],tot; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; } void init() { read(n); read(m); int u,v; for(int i=1;i<=m;i++) { read(u); read(v); add(u,v); } read(p); for(int i=1;i<=p;i++) read(cut[i][0]),read(cut[i][1]); } void dfs1(int x,int y) { fa[x][0]=y; siz[x]=1; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) dfs1(to[i],x),siz[x]+=siz[to[i]]; } void dfs2(int x,int top) { id[x]=++cnt; bl[x]=top; int y=0; for(int i=front[x];i;i=nxt[i]) if(to[i]!=fa[x][0] && siz[to[i]]>siz[y]) y=to[i]; if(!y) return; dfs2(y,top); for(int i=front[x];i;i=nxt[i]) if(to[i]!=fa[x][0] && to[i]!=y) dfs2(to[i],to[i]); } void prelca() { for(int i=1;i<=17;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; } int getlca(int u,int v) { if(u==v) return u; if(id[u]<id[v]) swap(u,v); for(int i=17;i>=0;i--) if(id[fa[u][i]]>id[v]) u=fa[u][i]; return fa[u][0]; } bool cmp(int a,int b) { return lca[a]<lca[b]; } void modify(int k,int l,int r,int pos) { f[k]=true; if(l==r) return; int mid=l+r>>1; if(pos<=mid) modify(k<<1,l,mid,pos); else modify(k<<1|1,mid+1,r,pos); } bool query(int k,int l,int r,int opl,int opr) { if(l==opl && r==opr) return f[k]; int mid=l+r>>1; if(opr<=mid) return query(k<<1,l,mid,opl,opr); if(opl>mid) return query(k<<1|1,mid+1,r,opl,opr); return query(k<<1,l,mid,opl,mid)|query(k<<1|1,mid+1,r,mid+1,opr); } bool QUERY(int u,int v) { while(bl[u]!=bl[v]) { if(id[u]<id[v]) swap(u,v); if(query(1,1,cnt,id[bl[u]],id[u])) return true; u=fa[bl[u]][0]; } return query(1,1,cnt,min(id[v],id[u]),max(id[v],id[u])) ; } void work(int x) { for(int i=front[x];i;i=nxt[i]) if(to[i]!=fa[x][0]) work(to[i]); for(int i=lr[x][0];i<=lr[x][1];i++) if(!QUERY(cut[q[i]][0],cut[q[i]][1])) { modify(1,1,cnt,id[x]); ans[++ans[0]]=x; return; } } void solve() { for(int i=1;i<=p;i++) lca[i]=getlca(cut[i][0],cut[i][1]),q[i]=i; sort(q+1,q+p+1,cmp); for(int i=1;i<=n;i++) lr[i][0]=p+1,lr[i][1]=0; for(int i=1;i<=p;i++) { lr[lca[q[i]]][0]=min(lr[lca[q[i]]][0],i); lr[lca[q[i]]][1]=max(lr[lca[q[i]]][1],i); } work(1); printf("%d\n",ans[0]); for(int i=1;i<=ans[0];i++) printf("%d ",ans[i]); } int main() { freopen("ping.in","r",stdin); freopen("ping.out","w",stdout); init(); dfs1(1,0); dfs2(1,1); prelca(); solve(); }