我打比赛打到自闭
话说这比赛真的有区分度吗,暴力能拿很多分诶
T1
随便写
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int read(){ 4 int x=0; bool f=1; char c=getchar(); 5 for(;!isdigit(c);c=getchar()) if(c=='-') f=0; 6 for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 7 if(f) return x; 8 return 0-x; 9 } 10 int e[33][33],r[33][33],c[33][33],n,m; 11 int main(){ 12 freopen("elim.in","r",stdin); 13 freopen("elim.out","w",stdout); 14 n=read(),m=read(); 15 int i,j; 16 for(i=1;i<=n;++i) 17 for(j=1;j<=m;++j) 18 e[i][j]=read(), 19 r[i][j]=(e[i][j]==e[i][j-1]) ? r[i][j-1]+1 : 1, 20 c[i][j]=(e[i][j]==e[i-1][j]) ? c[i-1][j]+1 : 1; 21 for(i=1;i<=n;++i) 22 for(j=1;j<=m;++j){ 23 if(r[i][j]>=3){ 24 if(r[i][j]==3) e[i][j-2]=e[i][j-1]=e[i][j]=0; 25 else e[i][j]=0; 26 } 27 if(c[i][j]>=3){ 28 if(c[i][j]==3) e[i-2][j]=e[i-1][j]=e[i][j]=0; 29 else e[i][j]=0; 30 } 31 } 32 for(i=1;i<=n;++i){ 33 for(j=1;j^m;++j) printf("%d ",e[i][j]); 34 printf("%d ",e[i][m]); 35 } 36 return 0; 37 }
T2
其实就是让你找每个人到安全区(圆)的最短路。
正着做(求每个人到圆的最短路)时间爆炸,考虑反过来做……
每次从安全区(圆)中的所有点开始向外 $bfs$,求出图中每个点到圆的最短路。由于相邻两格的距离都是 $1$,最先到达某个点的一条路径一定是最短路。时间复杂度是$O(n^2)$。
然而我是个傻逼,昨天刚提过的多源最短路今天就忘了……
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for(register int i=(x);i<=(y);i++) 3 #define dwn(i,x,y) for(register int i=(x);i>=(y);i--) 4 #define maxn 410 5 #define maxm 100010 6 #define maxnd (401*401) 7 using namespace std; 8 inline int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while(!isdigit(ch)&&ch!='-')ch=getchar(); 12 if(ch=='-')f=-1,ch=getchar(); 13 while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 14 return x*f; 15 } 16 inline void write(int x) 17 { 18 int f=0;char ch[20]; 19 if(!x){putchar('0'),putchar(' ');return;} 20 if(x<0)x=-x,putchar('-'); 21 while(x)ch[++f]=x%10+'0',x/=10; 22 while(f)putchar(ch[f--]); 23 putchar(' '); 24 } 25 int n,m,e,f,h,rx,ry,r; 26 int sx[maxm],sy[maxm],dis[maxn][maxn],no[maxn][maxn],lft[maxm],qx[maxnd],qy[maxnd],hd,tl; 27 int yes(int x,int y) 28 { 29 if(x<=n&&x>=1&&y<=n&&y>=1)return 1; 30 return 0; 31 } 32 int inr(int x,int y) 33 { 34 if((x-rx)*(x-rx)+(y-ry)*(y-ry)<=r*r)return 1; 35 return 0; 36 } 37 inline void push(int x,int y){tl++;qx[tl]=x,qy[tl]=y;return;} 38 int dtx[9]={-1,0,1,0,-1,-1,1,1},dty[9]={0,1,0,-1,-1,1,1,-1}; 39 void getdis() 40 { 41 hd=1,tl=0; 42 rep(i,1,n) 43 rep(j,1,n) 44 { 45 if(inr(i,j))push(i,j),dis[i][j]=0; 46 else dis[i][j]=maxnd; 47 } 48 while(hd<=tl) 49 { 50 int ux=qx[hd],uy=qy[hd];hd++; 51 rep(i,0,3) 52 { 53 int nx=ux+dtx[i],ny=uy+dty[i]; 54 if(yes(nx,ny)&&dis[nx][ny]==maxnd) 55 { 56 dis[nx][ny]=dis[ux][uy]+1; 57 if(!no[nx][ny])push(nx,ny); 58 } 59 } 60 rep(i,4,7) 61 { 62 int nx=ux+dtx[i],ny=uy+dty[i]; 63 if(yes(nx,ny)&&dis[nx][ny]==maxnd&&(!no[ux][ny]||!no[nx][uy])) 64 { 65 dis[nx][ny]=dis[ux][uy]+1; 66 if(!no[nx][ny])push(nx,ny); 67 } 68 } 69 } 70 } 71 int main() 72 { 73 freopen("battleground.in","r",stdin); 74 freopen("battleground.out","w",stdout); 75 n=read(),m=read(),e=read(),f=read(),h=read(); 76 rep(i,1,m)lft[i]=h; 77 rep(i,1,e){int x=read()+1,y=read()+1;no[x][y]=1;} 78 rep(i,1,m)sx[i]=read()+1,sy[i]=read()+1; 79 while(f--) 80 { 81 rx=read()+1,ry=read()+1,r=read(); 82 getdis(); 83 rep(i,1,m)lft[i]-=dis[sx[i]][sy[i]]; 84 rep(i,1,m)sx[i]=read()+1,sy[i]=read()+1; 85 } 86 rep(i,1,m)write(max(lft[i],0)); 87 return 0; 88 }
T3
两种做法。
一种是优先队列(set / 可删堆)维护。
一个优先队列记录所有度数为 $1$ 的点的度数和编号。归约用。
为什么不记录度数为 $0$ 的点?因为根据贪心策略,度数为 $0$ 的点一定只有一开始存在,然后最开始做归约就把它们删完了。剩下的所有点只要度数降到 $1$ 就会被删掉,所以不会再有点的度数变成 $0$ 了。
另一个优先队列记录所有度数大于等于 $2$ 的点,存三个关键字,依次是:点的度数(大到小),相邻节点中度为 $2$ 的点的个数(大到小),点的编号(大到小)。贪心删点用。
然后很明显了——题目看起来是说了一堆贪心操作,实际上它们就是一个关键字优先级排序,于是成了堆裸题。
贪心删点时,由于只有删点操作,所以所有点的度数是只减不加的,因此可以直接往堆中插入一个新的减过度数的点,它一定比原来没减度数的点先到达堆顶。所以只接受原图每个点在堆中第一次到达堆顶的信息就可以了。
暴力减去与删除点连接的所有未删除点的度数即可。
复杂度分析(最难考点):每个点只有在 当做堆顶 和 度为 $1$ 的时候会执行两次“把周围一圈点的度 $-1$ ”,对于无向图,所有点的度的和 = 边数$*2$ (每条边都让两端点的度数+1),整张图总共最多也就减这么多次度数。所以复杂度是对的。
不过由于我思想僵化,又没做出来。
没有这种做法的 $std$ ……先凑乎吧。
另一种是权值线段树,其实跟堆差不多。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N 100010 5 #define mid ((l+r)>>1) 6 using namespace std; 7 struct segt 8 { 9 int d[N<<2],a[N<<2],b[N<<2],v[N<<2]; 10 int chk1(int x,int y) 11 { 12 if (d[x]<0 && d[y]<0) return x;if (d[x]<0) return y;if (d[y]<0) return x; 13 if (d[x]<=d[y]) return x;if (d[x]>d[y]) return y; 14 } 15 int chk2(int x,int y) 16 { 17 if (d[x]<0 && d[y]<0) return y;if (d[x]<0) return y;if (d[y]<0) return x; 18 if (d[x]<d[y]) return y;if (d[x]>d[y]) return x; 19 if (v[x]<v[y]) return y;if (v[x]>v[y]) return x;return y; 20 } 21 void upd(int t,int l,int r,int x,int k1,int k2) 22 { 23 while (l<r) if (x<=mid) r=mid,t<<=1;else l=mid+1,t<<=1,t++; 24 d[t]+=k1,v[t]+=k2;a[t]=b[t]=t;t>>=1; 25 while (t){a[t]=chk1(a[t<<1],a[t<<1|1]);b[t]=chk2(b[t<<1],b[t<<1|1]);t>>=1;} 26 } 27 }sgt; 28 int n,fir[N],nxt[N*11],to[N*11],vis[N],cnt,du[N],pos[N<<2]; 29 void add(int u,int v){nxt[++cnt]=fir[u];fir[u]=cnt;to[cnt]=v;} 30 void del(int x) 31 { 32 int d=du[x],i,j;du[x]=-1;vis[x]=1;sgt.upd(1,1,n,x,-d-1,0); 33 for (i=fir[x];i;i=nxt[i]) if (!vis[to[i]]) 34 { 35 du[to[i]]--;sgt.upd(1,1,n,to[i],-1,-(d==2));if (du[to[i]]==2) 36 for (j=fir[to[i]];j;j=nxt[j]) if (!vis[to[j]]) sgt.upd(1,1,n,to[j],0,1); 37 if (du[to[i]]==1)for (j=fir[to[i]];j;j=nxt[j]) if (!vis[to[j]]) sgt.upd(1,1,n,to[j],0,-1); 38 } 39 } 40 int main() 41 { 42 freopen("greedy.in","r",stdin); 43 freopen("greedy.out","w",stdout); 44 int m,i,j,l,r,t;scanf("%d%d",&n,&m); 45 for (i=1;i<=m;i++) 46 { 47 scanf("%d%d",&l,&r),add(l,r),add(r,l); 48 sgt.upd(1,1,n,l,1,0);sgt.upd(1,1,n,r,1,0);du[l]++;du[r]++; 49 } 50 for (i=1;i<=n;i++) for (j=fir[i];j;j=nxt[j]) if (du[to[j]]==2) sgt.upd(1,1,n,i,0,1); 51 for (i=1;i<=n;i++){l=t=1;r=n;while (l<r) if (i<=mid) r=mid,t<<=1;else l=mid+1,t<<=1,t++;pos[t]=i;} 52 for (i=1;i<=n;i++) if (du[i]==0) printf("%d ",i),sgt.upd(1,1,n,i,-1,0),du[i]--; 53 while (1) 54 { 55 if (sgt.d[sgt.b[1]]<0) break;t=pos[sgt.a[1]]; 56 if (sgt.d[sgt.a[1]]==0) printf("%d ",t),sgt.upd(1,1,n,t,-1,0); 57 else if (sgt.d[sgt.a[1]]==1) 58 { 59 printf("%d ",t); 60 for (i=fir[t];i;i=nxt[i]) if (!vis[to[i]]) del(to[i]); 61 sgt.upd(1,1,n,t,-1,0); 62 } 63 else del(pos[sgt.b[1]]); 64 } 65 }