http://zhengruioi.com/contest/1030
\(51+100+0+0=151\)
T1 flew directly to the second power without pretreatment
A. Number tree
For a tree without edge weight, the distance between two points in the tree is defined as the number of edges that the path between two points passes through.
Now let me tell you a tree with \ (n \) points and \ (q \) query. The \ (I \) query gives \ (d_i \). How many point sets \ (S \) in the tree meet the distance between the two farthest points in the set is \ (d_i \). Because the answer may be too large, please take the module of \ (10 ^ 9 + 7 \).
\(q<n\le 2000\)
Consider enumerating the center of the point set diameter
Then enumerate the depth. It is required that at least one point of this depth appears in at least two subtrees, and the others can be selected randomly
If \ (d_i \) is an odd number, you can add an imaginary point in the middle of each edge
Power of preprocessing, \ (O(n^2) \)
#define mod 1000000007 #define N 4006 #define M 8006 long long power[N]; struct Graph{ int fir[N],nex[M],to[M],tot=1; inline void add(int u,int v,int flag=1){ to[++tot]=v; nex[tot]=fir[u];fir[u]=tot; // if(flag) printf(" %d %d\n",u,v); if(flag) add(v,u,0); } inline void clear(){std::memset(fir,0,sizeof fir);tot=0;} }G; int n; long long all[N],cnt[M][N]; long long allSum[N],cntSum[M][N]; void dfs(int u,long long *cnt,int fa=0,int deep=0){ cnt[deep]+=(u<=n);all[deep]+=(u<=n); for(int i=G.fir[u];i;i=G.nex[i])if(G.to[i]^fa) dfs(G.to[i],cnt,u,deep+1); } long long f[N]; inline void calc(int u,int op){ std::memset(all,0,sizeof all); for(int i=G.fir[u];i;i=G.nex[i]){ dfs(G.to[i],cnt[i],u,1); for(int d=1;d<=n<<1;d++) cntSum[i][d]=cntSum[i][d-1]+cnt[i][d]; } all[0]=allSum[0]=(u<=n); for(int d=1;d<=n<<1;d++) allSum[d]=allSum[d-1]+all[d]; if(op==1){ for(int d=4;d<n<<1;d+=4){ long long now=power[allSum[d>>1]]; now=(now-power[allSum[(d>>1)-1]]+mod)%mod; for(int i=G.fir[u];i;i=G.nex[i]){ long long sub=power[allSum[(d>>1)-1]-cntSum[i][(d>>1)-1]]*((power[cntSum[i][d>>1]]-power[cntSum[i][(d>>1)-1]]+mod)%mod)%mod; now=(now-sub+mod)%mod; } f[d>>1]=(f[d>>1]+now)%mod; } } else{ for(int d=2;d<n<<1;d+=4){ long long now=power[allSum[d>>1]]; now=(now-power[allSum[(d>>1)-1]]+mod)%mod; for(int i=G.fir[u];i;i=G.nex[i]){ long long sub=power[allSum[(d>>1)-1]-cntSum[i][(d>>1)-1]]*((power[cntSum[i][d>>1]]-power[cntSum[i][(d>>1)-1]]+mod)%mod)%mod; now=(now-sub+mod)%mod; } f[d>>1]=(f[d>>1]+now)%mod; } } } int main(){ // freopen("a1.in","r",stdin); n=read(); for(int i=1;i<n;i++) G.add(read(),i+n),G.add(read(),i+n); power[0]=1;for(int i=1;i<=n<<1;i++) power[i]=power[i-1]*2%mod; for(int i=1;i<=n;i++) calc(i,1); for(int i=n+1;i<n<<1;i++) calc(i,0); int q=read();while(q--) writeEN(f[read()]); return SUC_RETURN; }
B. Play chess
There are \ (m \) horses and \ (k \) soldiers on a \ (n\times n \) chessboard. Xiaozheng and Xiaorui are playing a game.
Xiaozheng is the first hand and Xiaorui is the second. Each hand can move a horse according to the rules of chess (move \ (2 \) units in one dimension and \ (1 \) units in the other dimension). The moved horse cannot move outside the chessboard, nor can it coincide with other horses and soldiers.
The first person who makes the situation repeat loses the game. The two situations \ (A \) and \ (B \) are not repeated. If and only if there is A certain position \ ((p,q) \), the \ ((p,q) \) of situation A has chess pieces, and the \ ((p,q) \) of situation \ (B \) has no chess pieces. Note: there is no difference between two horses.
Now tell you the position of each soldier, and the position of the horse is unknown. How many initial situations can Xiaozheng win?
\(n\le 15,1\le m\le 2\)
Consider building a graph for the transfer relationship between all situations, which is a bipartite graph:
- For \ (m=1 \), you can dye according to the parity of \ (x+y \)
- For \ (m=2 \), you can dye according to whether the parity of \ (x+y \) and \ (p+q \) are the same
If there is a maximum match so that a point is not a matching point, it must not be used as a starting point: the first hand must go to a matching point, and then the second hand will go to the matching edge. The first hand non matching edge must end with the matching edge, so the first hand has no way to go
So it becomes the problem of the maximum matching point of bipartite graph: https://www.cnblogs.com/suxxsfe/p/15414767.html
The number of points and edges is \ (O(n^{2m}) \), so the complexity is \ (O(n^{3m}) \)
#define N 60006 #define M 2000006 struct Graph{ int fir[N],nex[M],to[M],tot=1; int w[M],fir_[N]; inline void add(int u,int v,int d,int flag=1){ to[++tot]=v;w[tot]=d; nex[tot]=fir[u];fir[u]=tot; // if(flag) printf(" %d %d\n",u,v); if(flag) add(v,u,0,0); } inline void clear(){std::memset(fir,0,sizeof fir);tot=0;} }G,H; const int di[]={-2,-1,1,2,2,1,-1,-2}; const int dj[]={1,2,2,1,-1,-2,-2,-1}; int n,m,k; int id[22][22],no[22][22]; inline int check(int i,int j){return i>=1&&j>=1&&i<=n&&j<=n;} inline int getId(int i,int j){return (i-1)*id[0][0]+j;} int S,T; int deep[N]; int left,right,que[N]; inline int bfs(){ std::memset(deep,0,(T+1)*sizeof deep[0]); left=right=0; que[0]=S;deep[S]=1; int u; while(left<=right){ u=que[left++]; for(int v,i=G.fir[u];i;i=G.nex[i]){ v=G.to[i]; if(deep[v]||!G.w[i]) continue; deep[v]=deep[u]+1;que[++right]=v; if(v==T) return 1; } } return 0; } int dfs(int u,int now=INT_INF){ if(u==T) return now; long long res=now; for(int v,&i=G.fir_[u];i;i=G.nex[i]){ v=G.to[i]; if(deep[v]!=deep[u]+1||!G.w[i]) continue; int k=dfs(v,lib::min(res,G.w[i])); if(!k) deep[v]=0; else G.w[i]-=k,G.w[i^1]+=k,res-=k; if(!res) break; } return now-res; } inline int dinic(){ int ans=0; while(bfs()){ int now; std::memcpy(G.fir_,G.fir,(T+1)*sizeof G.fir[0]); while(now=dfs(S)) ans+=now; } return ans; } inline void build(){ if(m==1){ for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j]){ if((i+j)&1) G.add(S,id[i][j],1); else G.add(id[i][j],T,1); } for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j]&&((i+j)&1)){ for(int i_,j_,k=0;k<8;k++){ i_=i+di[k];j_=j+dj[k]; if(!check(i_,j_)||no[i_][j_]) continue; G.add(id[i][j],id[i_][j_],1); } } } else if(m==2){ for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j])for(int x=1;x<=n;x++)for(int y=1;y<=n;y++)if(!no[x][y]&&(x!=i||y!=j)){ if(((i+j)&1)==((x+y)&1)) G.add(S,getId(id[i][j],id[x][y]),1); else G.add(getId(id[i][j],id[x][y]),T,1); } for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j])for(int x=1;x<=n;x++)for(int y=1;y<=n;y++)if(!no[x][y]&&(((i+j)&1)==((x+y)&1))&&(x!=i||y!=j)){ for(int i_,j_,x_,y_,k=0;k<8;k++){ i_=i+di[k];j_=j+dj[k];x_=x;y_=y; if(!check(i_,j_)||no[i_][j_]) goto NO; G.add(getId(id[i][j],id[x][y]),getId(id[i_][j_],id[x_][y_]),1); NO: i_=i;j_=j;x_=x+di[k];y_=y+dj[k]; if(!check(x_,y_)||no[x_][y_]) continue; G.add(getId(id[i][j],id[x][y]),getId(id[i_][j_],id[x_][y_]),1); } } } } int color[N],vis[N],noNeed[N]; inline void rebuild(int k){ std::memset(color,0,sizeof color);std::memset(vis,0,sizeof vis); for(int u,i=G.fir[k?T:S];i;i=G.nex[i]){ u=G.to[i]; if(G.w[i]^k) noNeed[u]=1; color[u]=1; for(int v,j=G.fir[u];j;j=G.nex[j]){ v=G.to[j]; if(G.w[j]^k) H.add(u,v,0,0);//no match else H.add(v,u,0,0); } } } void dfs2(int u){ if(vis[u]) return; vis[u]=1;if(color[u]) noNeed[u]=1; for(int i=H.fir[u];i;i=H.nex[i]) dfs2(H.to[i]); } inline void work(){ rebuild(1);//0=left, 1=right for(int i=G.fir[T];i;i=G.nex[i])if(!G.w[i]) dfs2(G.to[i]); H.clear(); rebuild(0); for(int i=G.fir[S];i;i=G.nex[i])if(G.w[i]) dfs2(G.to[i]); } int main(){ n=read();m=read();k=read(); for(int x,i=1;i<=k;i++) x=read(),no[x][read()]=1; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j]) id[i][j]=++id[0][0]; if(m==1) S=id[0][0]+1,T=S+1; else if(m==2) S=id[0][0]*id[0][0]+1,T=S+1; build(); // printf("%d\n",G.tot); dinic(); work(); int ans=0; if(m==1){ for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j]&&!noNeed[id[i][j]]) ans++; } else if(m==2){ for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!no[i][j]){ for(int x=1;x<=n;x++)for(int y=1;y<=n;y++)if(!no[x][y]&&!noNeed[getId(id[i][j],id[x][y])]&&(x!=i||y!=j)) ans++; } ans>>=1; } writeEN(ans); return SUC_RETURN; }
C. Walk
There is a tree with \ (n \) points, and the edge of the tree has edge weight.
On this basis, some multiple edges are added to the tree (the points connected by the added edges are also directly connected by an edge in the original tree).
Give \ (Q \) queries. The content of each query is: ask how many times the edge weight can be switched for a pair of points \ (p,q \) from \ (p \) to \ (Q \) without passing through repeated points. On the path, if the edge weights of adjacent edges are different, the edge weights are switched once.
\(n\le 5\times 10^5,m\le 10^6\)
One idea is to find out how many times \ (u \) up \ (2^i \) will be switched by doubling in the tree, but you find that you still need to record what is on both sides, otherwise you can't merge
In this case, there may be a lot of combinations and it will explode
However, if there are more than three combinations of edge weights on both sides, switching will occur on both sides, so only three can be recorded
\(O(n\log n)\)
#define N 500006 #define M 2000006 struct Graph{ int fir[N],nex[M],to[M],tot=1; inline void add(int u,int v,int flag=1){ to[++tot]=v; nex[tot]=fir[u];fir[u]=tot; if(flag) add(v,u,0); } inline void clear(){__builtin_memset(fir,0,sizeof fir);tot=0;} }G; struct Node{ int ans,size,s[3],t[3]; inline void clear(){__builtin_memset(this,0,sizeof(Node));} inline Node operator + (const Node &o){ if(!size) return o; if(!o.size) return *this; Node ret;ret.clear(); for(int i=0;i<size;i++)for(int j=0;j<o.size;j++)if(t[i]^o.s[j]){ ret.s[ret.size]=s[i];ret.t[ret.size]=o.t[j];ret.size++; ret.ans=ans+o.ans+1; if(ret.size==3) goto FULL; } FULL: if(!ret.size){ ret.size=1;ret.s[0]=s[0];ret.t[0]=o.t[0]; ret.ans=ans+o.ans; } return ret; } inline void insert(int o){ if(size==3) return; s[size]=o;t[size++]=o; } inline void operator = (const Node &o){__builtin_memcpy(this,&o,sizeof(Node));} }; #define MAX 20 Node ans[22][N]; int fa[22][N],deep[N]; std::vector<int>edge[N]; void pre(int u){ for(int v,i=G.fir[u];i;i=G.nex[i]){ v=G.to[i]; if(v==fa[0][u]||fa[0][v]) continue; fa[0][v]=u; pre(v); } } void dfs(int u){ deep[u]=deep[fa[0][u]]+1; for(int v,i=G.fir[u];i;i=G.nex[i]){ v=G.to[i]; if(v==fa[0][u]||deep[v]) continue; fa[0][v]=u; for(int o:edge[v]) ans[0][v].insert(o); for(int j=1;j<MAX;j++){ fa[j][v]=fa[j-1][fa[j-1][v]]; ans[j][v]=ans[j-1][v]+ans[j-1][fa[j-1][v]]; } dfs(v); } } inline int calc(int x,int y){ if(x==y) return 0; if(deep[x]<deep[y]) lib::swap(x,y); Node A,B;A.clear();B.clear(); for(int i=MAX-1;~i;i--)if(deep[fa[i][x]]>=deep[y]) A=A+ans[i][x],x=fa[i][x]; if(x==y) return A.ans; for(int i=MAX-1;~i;i--)if(fa[i][x]^fa[i][y]) A=A+ans[i][x],B=B+ans[i][y],x=fa[i][x],y=fa[i][y]; A=A+ans[0][x];B=B+ans[0][y]; for(int i=0;i<A.size;i++)for(int j=0;j<B.size;j++)if(A.t[i]^B.t[j]) return A.ans+B.ans+1; return A.ans+B.ans; } int n,m; int u[M],v[M],w[M]; int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ u[i]=read();v[i]=read();w[i]=read(); G.add(u[i],v[i]); } pre(1); for(int i=1;i<=m;i++){ if(fa[0][u[i]]==v[i]) edge[u[i]].push_back(w[i]); else edge[v[i]].push_back(w[i]); } dfs(1); int q=read();while(q--){ int x=read(),y=read(); writeEN(calc(x,y)); } return SUC_RETURN; }
D. Open loop
There is a necklace with \ (n \) beads, each with a letter written on it.
Please choose a position to break the necklace into a chain. We assume that the sequence after breaking and the sequence of input are clockwise.
For the obtained chain, please divide it into \ (k \) consecutive parts to meet the minimum dictionary order of the largest dictionary order in these parts. Please output the largest part of the dictionary.
\(n\le 5\times 10^5\)