省選模擬20
阿新 • • 發佈:2022-02-23
今天又是沒改完題的一天!!!
考場心態越來越好!!做題策略也有些改進,趁著自己昏昏欲睡的時候就不要想了,而是先把暴力打了!
第一題,一眼就切了,一下就過樣例了,手造了一個一下就假了,完事一下就不會了...
第二題,一下就想到了最小割樹,一度認為自己已經切掉了此題,然後發現只有40
第三題,一下就看到了是特判題,這次認為穩穩的切了,然而有兩個impossible判錯了,於是掛沒了
T1 定位系統
目前只會50分,LCT上二分頹難了
總而言之,DP的思想對於這種題來說非常的重要,其實考場上意識到了和單鏈有關係,然而沒有找到具體的關係!!
我們可以通過dp式子找到一定的關係,甚至可以推出來是一個定值!
於是這個題就可以這樣一步一步的化簡到非常好求的程度!!
50_code
#include<bits/stdc++.h> using namespace std; #define fo(i,x,y) for(int i=(x);i<=(y);i++) #define fu(i,x,y) for(int i=(x);i>=(y);i--) int read(){ int s=0,t=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();} while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} return s*t; } const int N=5e5+5; int n,q,ans; int du[N]; struct D{int x,y;}d[N]; struct E{int to,nxt;}e[N*2]; int head[N],rp; void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;} int cnt[N],mxd[N]; void dfs_rt(int x,int f){ mxd[x]=du[x];cnt[x]=0; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(y==f)continue; dfs_rt(y,x);if(mxd[y]<=2)cnt[x]++; mxd[x]=max(mxd[x],mxd[y]); } } void dfs_dp(int x,int f){ for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(y==f)continue; if(mxd[y]<=2&&((du[x]==2&&cnt[x]==2)||(du[x]==1&&cnt[x]==0)))cnt[y]++; if(mxd[y]>2&&((du[x]==2&&cnt[x]==1)||(du[x]==1&&cnt[x]==0)))cnt[y]++; dfs_dp(y,x); } } int ck(){ if(n==1)return 0; bool flag=true; fo(i,1,n)if(du[i]>2)flag=false; if(flag)return 1;rp=ans=0; memset(head,0,sizeof(int)*(n+1)); fo(i,1,n-1)add_edg(d[i].x,d[i].y),add_edg(d[i].y,d[i].x); dfs_rt(1,0);dfs_dp(1,0); fo(i,1,n)ans+=max(0,cnt[i]-1);//cerr<<i<<" "<<du[i]<<" "<<mxd[i]<<" "<<cnt[i]<<endl; return ans; } signed main(){ freopen("location.in","r",stdin); freopen("location.out","w",stdout); n=read(); fo(i,1,n-1){ d[i].x=read(); d[i].y=read(); du[d[i].x]++;du[d[i].y]++; } q=read();printf("%d\n",ck()); while(q--){ int u=read(),v=read(); int x=read(),y=read(); du[u]--;du[v]--;du[x]++;du[y]++; fo(i,1,n-1)if((d[i].x==u&&d[i].y==v)||(d[i].x==v&&d[i].y==u))d[i].x=x,d[i].y=y; printf("%d\n",ck()); } return 0; }
T2 簽到題
首先我發現了最大的可能的最大流是3,但是沒有想到什麼好辦法
於是我們可以看題解!!!這個就是利用隨機權值來判斷兩條邊割掉之後是否可以使得圖不聯通
AC_code
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long #define fo(i,x,y) for(int i=(x);i<=(y);i++) #define fu(i,x,y) for(int i=(x);i>=(y);i--) int read(){ int s=0,t=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();} while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} return s*t; } random_device you; mt19937 pyt(you()); ull rd(){return 1ull*pyt()*pyt();} const int N=1e6+5; int n,m;ull ans; struct E{int to,nxt;ull val;}e[N*6]; int head[N],rp=1,ban[N*6]; void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;} int sz0[N];bool vis[N]; void dfs0(int x,int f){ sz0[x]=1;vis[x]=true; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(y==f||vis[y])continue; dfs0(y,x);sz0[x]+=sz0[y]; } //cerr<<"dfs0"<<" "<<x<<" "<<sz0[x]<<endl; } int dfn[N],low[N],cnt; int bl[N],cbl,sz1[N],brt[N],sta[N],top; void tarjan(int x){ dfn[x]=low[x]=++cnt;sta[++top]=x; for(int i=head[x];i;i=e[i].nxt){ if(ban[i])continue; int y=e[i].to;ban[i]=ban[i^1]=true; if(!dfn[y])tarjan(y),low[x]=min(low[x],low[y]); else if(!bl[y])low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ bl[x]=++cbl;sz1[cbl]=1; while(sta[top]!=x)bl[sta[top--]]=cbl,sz1[cbl]++; top--;brt[cbl]=x; } } int fe[N],ji[N],cj,dep[N]; ull val[N]; void dfs_cl(int x,int f,int blg){ vis[x]=true;dep[x]=dep[f]+1; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(bl[y]!=blg)continue; ban[i]=ban[i^1]=false; if(vis[y])continue; dfs_cl(y,x,blg); } } void dfs_fg(int x,int f,int blg){ ji[++cj]=x;dep[x]=dep[f]+1;vis[x]=true; for(int i=head[x];i;i=e[i].nxt){ if(ban[i])continue; int y=e[i].to;ban[i]=ban[i^1]=true; if(y==f||bl[y]!=blg)continue; if(vis[y]){ ull tmp=rd(); //cerr<<"FZ"<<" "<<x<<" "<<y<<endl; e[fe[x]].val^=tmp; e[fe[y]].val^=tmp; continue; } fe[y]=i;dfs_fg(y,x,blg); e[fe[x]].val^=e[i].val; } } bool com(int x,int y){ if(e[fe[x]].val==e[fe[y]].val)return dep[x]<dep[y]; return e[fe[x]].val<e[fe[y]].val; } int fzb[N]; void dfs_fz(int x,int f,int blg){ vis[x]=true;dep[x]=dep[f]+1; for(int i=head[x];i;i=e[i].nxt){ if(ban[i])continue; int y=e[i].to;ban[i]=ban[i^1]=true; if(y==f||bl[y]!=blg)continue; if(vis[y]){fzb[y]--;fzb[x]++;continue;} dfs_fz(y,x,blg);fzb[x]+=fzb[y]; } if(fzb[x]<=1)val[x]^=rd(); } void dfs_xf(int x,int f,int blg){ vis[x]=true; for(int i=head[x];i;i=e[i].nxt){ if(ban[i])continue; int y=e[i].to;ban[i]=ban[i^1]=true; if(y==f||bl[y]!=blg)continue; if(vis[y])continue; val[y]^=val[x];dfs_xf(y,x,blg); } } bool con(int x,int y){return val[x]<val[y];} signed main(){ freopen("juice.in","r",stdin); freopen("juice.out","w",stdout); n=read();m=read(); fo(i,1,m){ int x=read(),y=read(); add_edg(x,y);add_edg(y,x); } //cout<<"SB"<<endl; fo(i,1,n){ if(!sz0[i])dfs0(i,0);//cerr<<i<<" "<<sz0[i]<<endl; else sz0[i]=0; } fo(i,1,n)vis[i]=false; //cout<<"SB"<<endl; fo(i,1,n)if(sz0[i]){ int now=cbl+1; tarjan(i);//cerr<<cbl<<endl; fo(j,now,cbl)ans+=1ull*sz1[j]*(sz0[i]-sz1[j]);//cout<<sz1[j]<<" "<<sz0[i]<<endl; } memset(ban,false,sizeof(ban)); cerr<<ans<<endl; fo(i,1,cbl){cj=0; dfs_fg(brt[i],0,i);sort(ji+1,ji+cj+1,com); fo(j,1,cj)vis[ji[j]]=false; dfs_cl(brt[i],0,i);fo(j,1,cj)vis[ji[j]]=false; //cerr<<e[fe[2]].val<<" "<<e[fe[6]].val<<endl; fo(j,2,cj)if(e[fe[ji[j]]].val==e[fe[ji[j-1]]].val){ ull tmp=rd();val[ji[j]]^=tmp;val[ji[j-1]]^=tmp; //cerr<<"SB"<<" "<<ji[j]<<" "<<ji[j-1]<<endl; } dfs_fz(brt[i],0,i);fo(j,1,cj)vis[ji[j]]=false; dfs_cl(brt[i],0,i);fo(j,1,cj)vis[ji[j]]=false; dfs_xf(brt[i],0,i);fo(j,1,cj)vis[ji[j]]=false; dfs_cl(brt[i],0,i);fo(j,1,cj)vis[ji[j]]=false; sort(ji+1,ji+cj+1,con);int now=1; ji[cj+1]=0;val[0]=0; fo(j,2,cj+1){ //cerr<<ji[j-1]<<" "; if(val[ji[j]]!=val[ji[j-1]]){ ans+=3ull*now*(now-1); ans+=2ull*now*(cj-now); now=0;//cerr<<endl; }now++; } } printf("%llu",ans/2); }
T3 卷王
直接分1,2,3種情況特判就行了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int N=1e6+5;
int n,p[N];
int buc[N],sum;
void spj1(){
if(!buc[0]){
if(n==1)printf("Possible");
else printf("Impossible");
return ;
}
else {
if(n<4){printf("Impossible");return ;}
printf("Possible\n");
fo(i,2,n)printf("1 %d\n",i);
}
}
void spj2(){
int fi,se,las,sum;
fo(i,0,n)if(buc[i]){fi=i;break;}
fo(i,0,n)if(buc[i]&&i!=fi)se=i;
if(buc[0]){
if(buc[0]==1||p[se]){printf("Impossible");return ;}
if(buc[0]>=(n-1>>1)&&buc[se]<=2){printf("Impossible");return ;}
las=se;sum=0;printf("Possible\n");
fo(i,1,n)if(p[i]==0&&i!=se){
if(sum<min(buc[0],buc[se])-1)printf("%d %d\n",las,i),las=i,sum++;
else printf("%d %d\n",las,i);
}
sum=0;fo(i,1,n)if(p[i]==se){
if(sum<min(buc[0],buc[se]-1)-1)printf("%d %d\n",las,i),las=i,sum++;
else printf("%d %d\n",las,i);
}
return ;
}
else {
if(n==2){printf("Possible\n1 2\n");return ;}
if(n==3||p[se]==se||p[fi]==fi){printf("Impossible");return ;}
if(buc[fi]!=buc[se]&&min(buc[fi],buc[se])==2){printf("Impossible");return ;}
if(buc[fi]>buc[se])swap(fi,se);
printf("Possible\n");las=se;
fo(i,1,n)if(p[i]==fi&&i!=se){printf("%d %d\n",las,i);las=i;}
int beh;fo(i,1,n)if(p[i]==se&&i!=fi){beh=i;break;}sum=0;
fo(i,1,n)if(p[i]==se&&i!=fi&&sum<buc[fi]-1){printf("%d %d\n",las,i);las=i;sum++;}
printf("%d %d\n",las,fi);
fo(i,las+1,n)if(p[i]==se&&i!=fi){printf("%d %d\n",beh,i);}
}
}
void spj3(){
if(!buc[0]){printf("Impossible");return ;}
int fi,se,las,sum;
fo(i,1,n)if(buc[i]){fi=i;break;}
fo(i,1,n)if(buc[i]&&i!=fi)se=i;
if(p[fi]!=se||p[se]!=fi){printf("Impossible");return ;}
if(min(buc[fi],buc[se])<=2){printf("Impossible");return ;}
printf("Possible\n");//cerr<<buc[fi]<<" "<<buc[0]<<" "<<buc[se]<<endl;
if(buc[fi]>buc[se])swap(fi,se);
las=se;fo(i,1,n)if(p[i]==fi&&i!=se){printf("%d %d\n",las,i);las=i;}
int beh;fo(i,1,n)if(p[i]==se&&i!=fi){beh=i;break;}sum=0;
fo(i,1,n)if(p[i]==0){
if(p[las]==fi)printf("%d %d\n",las,i),las=i;
else printf("%d %d\n",las,i);
}
fo(i,1,n)if(p[i]==se&&i!=fi&&sum<buc[fi]-1){printf("%d %d\n",las,i);las=i;sum++;}
printf("%d %d\n",las,fi);
fo(i,las+1,n)if(p[i]==se&&i!=fi){printf("%d %d\n",beh,i);}
}
signed main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read();
fo(i,1,n){
p[i]=read();
if(p[i]==-1)p[i]=0;
buc[p[i]]++;
if(buc[p[i]]==1)sum++;
}
if(sum==1){spj1();return 0;}
if(sum==2){spj2();return 0;}
if(sum==3){spj3();return 0;}
printf("Impossible");
return 0;
}