【清華集訓2014】蟲逢 另解
阿新 • • 發佈:2021-12-23
題意
有 \(2n\) 個 \(m\) 位 \(01\) 串,每個串有恰好 \(L\) 個位置為 \(1\)。保證存在一個串的完美匹配,使得每對匹配都有恰好 \(\frac{L}{2}\) 個公共的 \(1\),請找出這些匹配。
資料生成方法:先分別地均勻隨機 \(n\) 對匹配的串,再隨機打亂。\(n,m=16900,L=130\)。
分析
考慮一對匹配串,它們有 \(\frac{L}{2}\) 個公共的 \(1\)。我們考慮把 \(m\) 位劃分成 \(B=\frac{L}{2}-1\) 個集合,這樣一定存在某個集合中有多個公共 \(1\)。
因此我們對每個集合分別做,依次列舉每個串在集合中為 \(1\)
分析一下複雜度。首先二元組總個數是 \(O(\frac{nL^2}{B})=O(L^3)\) 的。其次一對非匹配串的期望檢查次數是 \(O(\frac{1}{B})=O(\frac{1}{L})\)。你可以跑這個演算法兩遍達到 \(O(\frac{n^2}{L^2})=O(n)\) 次檢查。但是隻做一遍,再把某個串已經有匹配的情況剪枝掉就過了。
實現
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=(a),_=(b);i<=_;++i) #define per(i,a,b) for(int i=(a),_=(b);i>=_;--i) #define nc() (i1==i2&&(i2=(i1=in)+fread(in,1,T,stdin),i1==i2)?-1:*i1++) using namespace std; const int T=1<<20,M=135,mod=34981; char in[T],*i1=in,*i2=in; int n,m,L,B,a[mod][M],p[mod],st[M],res[mod]; int rd(int x=0,char c=0){ do c=nc();while(c<48||c>57); do x=10*x+(c&15),c=nc();while(c>=48&&c<=57); return x; } struct HT{ int cnt,lnk[mod],nxt[mod*5],to[mod*5]; int ins(int x,int p){ for(int i=lnk[p];i;i=nxt[i])if(to[i]==x)return i; return nxt[++cnt]=lnk[p],to[cnt]=x,lnk[p]=cnt; } void init(){ cnt=0,memset(lnk,0,sizeof(lnk)); } }P; void chk(int u,int v){ if(res[u]||res[v])return; int i=1,j=1,w=0; while(i<=L&&j<=L){ if(a[u][i]==a[v][j])++i,++j,++w; else a[u][i]<a[v][j]?++i:++j; } if(w==L>>1)res[u]=v,res[v]=u; } int main(){ n=rd(),m=rd(),L=rd(); rep(i,1,n*2){ rep(j,1,L){ int x=0; rep(k,0,3)x=(x<<7)|nc(); a[i][j]=P.ins(x,x%mod); } sort(a[i]+1,a[i]+L+1),p[i]=1; } B=(m-1)/(L/2-1)+1; rep(k,1,(m-1)/B+1){ P.init(); rep(i,1,n*2){ st[0]=0; for(;p[i]<=L&&a[i][p[i]]<=k*B;p[i]++)st[++st[0]]=a[i][p[i]]-1-(k-1)*B; rep(u,1,st[0])rep(v,1,u-1)P.ins(i,(((st[u]-1)*st[u])>>1)+st[v]); } rep(i,0,mod-1){ st[0]=0; for(int j=P.lnk[i];j;j=P.nxt[j])st[++st[0]]=P.to[j]; rep(u,1,st[0])rep(v,1,u-1)chk(st[v],st[u]); } } rep(i,1,n*2)printf("%d\n",res[i]); return 0; }