倆紅夾一綠。什麼破分。。。
$T1$寫的和正解差不多的隨機化,然而特判有一句話寫錯了,$100 \rightarrow 0$
$T3$寫的$70pts$部分分。然而並不知道哪裏又寫掛了,雖然思路沒問題但是也是$70 \rightarrow 0$
$T3$大概是會正解的但是不太敢考場打$LCT$,必炸無疑,就算了(結果還是個$0$。。。)
得虧$T2$沒炸。不然爆零是如此輕鬆。。。
本來是比較簡單一套題怎麼又能考成這樣
T1:小B的棋盤
大意:有$n$個棋子,你可以再放$k$個,棋子之間不可重疊。問有多少可能的對稱中心。$n \le 10^5,k \le 20$
首先一個奇怪的隨機化:枚舉配對關係來確定對稱中心。
對於任意一個對稱中心有$n$個配對關係。一共$n^2$種方案。所以每次有$\frac{1}{n}$的成功率。
隨機次數足夠就不會出錯。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int S=100005,m=7000009; 4 int hsh(int x,int y){return ((x*19260817ll+y)%m+m)%m;} 5 struct hash_map{ 6 int fir[m],tx[m],ty[m],l[m],ec; 7 bool find(int x,int y){for(int i=fir[hsh(x,y)];i;i=l[i])if(tx[i]==x&&ty[i]==y)return 1;return 0;} 8 void ins(int x,int y){int r=hsh(x,y);l[++ec]=fir[r];fir[r]=ec;tx[ec]=x;ty[ec]=y;} 9 }P,A; 10 struct Hash_map{ 11 int fir[m],tx[m],ty[m],ec,v[m],l[m]; 12 int&find(int x,int y){ 13 int r=hsh(x,y); 14 for(int i=fir[r];i;i=l[i])if(tx[i]==x&&ty[i]==y)return v[i]; 15 l[++ec]=fir[r];fir[r]=ec;tx[ec]=x;ty[ec]=y;return v[ec]; 16 } 17 }M; 18 int x[S],y[S],n,k,ans,p[S]; 19 int chk(int X,int Y,int r=k){cerr<<X<<' '<<Y<<endl; 20 for(int i=1;i<=n&&r>=0;++i)if(!P.find(X-x[i],Y-y[i]))r--; 21 return r>=0; 22 } 23 int main(){ 24 scanf("%d%d",&n,&k); 25 if(n<=k)return puts("-1"),0; 26 for(int i=1;i<=n;++i)scanf("%d%d",&x[i],&y[i]),p[i]=i,P.ins(x[i],y[i]); 27 if(n<=100){ 28 for(int i=1;i<=n;++i)for(int j=i;j<=n;++j)if(!A.find(x[i]+x[j],y[i]+y[j])){ 29 A.ins(x[i]+x[j],y[i]+y[j]); 30 ans+=chk(x[i]+x[j],y[i]+y[j]); 31 }return printf("%d\n",ans),0; 32 } 33 while(clock()<950000){ 34 random_shuffle(p+1,p+1+n); 35 for(int i=1;i<=n;++i){ 36 int a=i,b=p[i]; 37 if(a>b)swap(a,b); if(A.find(a,b))continue; A.ins(a,b); 38 int&z=M.find(x[a]+x[b],y[a]+y[b]); 39 if(z==1)ans+=chk(x[a]+x[b],y[a]+y[b]); z++; 40 } 41 }printf("%d\n",ans); 42 }
正解的話,考慮任意定義一個偏序關係(橫縱座標啥的)然後前$k+1$個和後$k+1$個一定至少存在一個配對關係。枚舉就完了。$O(k^2n)$
T2:小B的夏令營
大意:$n+2$層的,每層$m$個房間樓,除了頂層和底層,每一天,每一層的最左側和最右側的一個房間都有$\frca{a}{b}$的概率被摧毀。
求$k$天之後整個房子還是一個聯通塊的概率。$n,m \le 1500,k \le 10^5$
暴力$dp$的話,可以設$dp[i][l][r]$表示第$i$層$[l,r]$還沒壞的概率。$O(n^5)$
可以直接前綴和優化。$O(n^3)$
觀察轉移式子可知我們不需要維護原值而只需要維護前綴和數組。$O(n^2)$
1 #include<cstdio> 2 const int mod=1e9+7,S=1555; 3 int f[S],F[S],L[S],R[S],FL[S],FR[S],n,m,k,p,q,fac[100005],inv[100005],l[S],r[S]; 4 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 5 int C(int b,int t){return 1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;} 6 int mo(int a){return a>=mod?a-mod:a;} 7 int main(){ 8 scanf("%d%d%d%d%d",&n,&m,&p,&q,&k); 9 for(int i=fac[0]=1;i<=k;++i)fac[i]=1ll*i*fac[i-1]%mod; 10 inv[k]=qp(fac[k],mod-2); 11 for(int i=k-1;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod; 12 p=1ll*p*qp(q,mod-2)%mod; q=mod+1-p; 13 for(int i=0;i<=m&&i<=k;++i)f[i]=C(k,i)*1ll*qp(p,i)%mod*qp(q,k-i)%mod; 14 F[0]=f[0]; 15 for(int i=1;i<=m;++i)F[i]=mo(F[i-1]+f[i]); 16 R[m]=L[1]=1; 17 for(int i=1;i<=m;++i)FR[i]=(FR[i-1]+1ll*f[i-1]*mo(mod+R[m]-R[i-1]))%mod; 18 for(int i=m;i>=1;--i)FL[i]=(FL[i+1]+1ll*f[m-i]*mo(mod+L[1]-L[i+1]))%mod; 19 for(int _=1;_<=n;++_){ 20 for(int i=1;i<=m;++i)r[i]=mo((r[i-1]-1ll*f[m-i]*L[i+1]%mod*F[i-1]+1ll*f[m-i]*FR[i])%mod+mod); 21 for(int i=m;i>=1;--i)l[i]=mo((l[i+1]-1ll*f[i-1]*R[i-1]%mod*F[m-i]+1ll*f[i-1]*FL[i])%mod+mod); 22 for(int i=1;i<=m;++i)L[i]=l[i],R[i]=r[i]; 23 for(int i=1;i<=m;++i)FR[i]=(FR[i-1]+1ll*f[i-1]*mo(mod+R[m]-R[i-1]))%mod; 24 for(int i=m;i>=1;--i)FL[i]=(FL[i+1]+1ll*f[m-i]*mo(mod+L[1]-L[i+1]))%mod; 25 }printf("%d\n",R[m]); 26 }
T3:小B的圖
大意:$n$個點,邊帶權,兩張聯通圖$A,B$。$A$圖的邊每選一條要額外付出$x$代價。$B$圖的邊$-x$。
多次給定不同的$x$求最小生成樹。$n \le 10^5,|A|,|B| \le 2 \times 10^5,-10^9 \le x,w_i \le 10^9$
首先,不管什麼$x$,你選出的邊一定要麼是$A$的最小生成樹邊,要麼是$B$的最小生成樹邊。
我們搞出$A$的最小生成樹,把$B$的邊從小到大依次加入替代$A$邊。
每條邊替換時我們能知道這條邊在$ \ge x_0$時纔會被替換。
排個序然後每次詢問二分就行。
很開心這次$LCT$沒有調太久。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 char in[23333333],*p=in; 4 void In(int&x){x=0;int f=0;while(*p<48||*p>57)f=*p++=='-';while(*p>47&&*p<58)x=x*10+*p++-48;x=f?-x:x;} 5 const int S=500005,inf=1e9+7; 6 #define ll long long 7 int n,A,B,q,X[S],g[S],oA[S],oB[S]; ll ans[S]; 8 struct E{int a,b,k,u;friend bool operator<(E x,E y){return x.k<y.k;}}e[S],Xe[S]; 9 bool cmp(E a,E b){return a.u<b.u;} 10 int find(int x){return x==g[x]?x:g[x]=find(g[x]);} 11 12 int v[S],vp[S],mx[S],c[S][2],f[S],lz[S],s[S]; 13 #define lc c[p][0] 14 #define rc c[p][1] 15 bool nr(int p){return c[f[p]][0]==p||c[f[p]][1]==p;} 16 void rev(int p){lz[p]^=1;swap(lc,rc);} 17 void down(int p){if(lz[p])rev(lc),rev(rc),lz[p]=0;} 18 void up(int p){mx[vp[p]=p]=v[p];for(int i=0;i<2;++i)if(mx[c[p][i]]>mx[p])mx[p]=mx[c[p][i]],vp[p]=vp[c[p][i]];} 19 void spin(int p){ 20 int F=f[p],G=f[F],D=c[F][1]==p,B=c[p][!D]; 21 if(nr(F))c[G][c[G][1]==F]=p; c[p][!D]=F; c[F][D]=B; 22 f[f[f[B]=F]=p]=G; up(F); 23 } 24 void push(int p){if(nr(p))push(f[p]);down(p);} 25 void splay(int p){push(p);for(;nr(p);spin(p)); up(p);} 26 void access(int r){for(int p=r,y=0;p;p=f[y=p])splay(p),rc=y,up(p);splay(r);} 27 void make(int p){access(p);rev(p);} 28 void link(int a,int b){make(a);f[a]=b;} 29 void split(int a,int b){make(a);access(b);} 30 void cut(int a,int b){split(a,b);f[a]=c[b][0]=0;up(b);} 31 32 int main(){ 33 fread(in,1,23333333,stdin); 34 In(n);In(A);In(B);In(q); mx[0]=-inf; 35 for(int i=1;i<=A;++i)In(e[i].a),In(e[i].b),In(e[i].k); 36 sort(e+1,e+1+A); 37 for(int i=1;i<=n;++i)g[i]=i,v[i]=-1e9; 38 for(int i=1;i<=A;++i){ 39 int x=find(e[i].a),y=find(e[i].b); 40 if(x==y)continue; 41 g[x]=y; ans[0]+=e[i].k; 42 v[i+n]=e[i].k; link(oA[i+n]=e[i].a,i+n); link(i+n,oB[i+n]=e[i].b); 43 } 44 for(int i=1;i<=B;++i)In(e[i].a),In(e[i].b),In(e[i].k); 45 sort(e+1,e+1+B); 46 for(int i=1;i<=n;++i)g[i]=i; 47 for(int i=1,z=0;i<=B;++i){ 48 int x=find(e[i].a),y=find(e[i].b); 49 if(x==y)continue; 50 g[x]=y; split(e[i].a,e[i].b); int _=vp[e[i].b]; 51 e[i].u=e[i].k-v[_]; Xe[++z]=e[i]; 52 cut(oA[_],_); cut(oB[_],_); link(e[i].a,e[i].b); 53 } 54 sort(Xe+1,Xe+n,cmp); 55 for(int i=1;i<n;++i)X[i]=(Xe[i].u+1)/2,ans[i]=ans[i-1]+Xe[i].u; 56 for(int _=1,x;_<=q;++_){ 57 In(x); int c=upper_bound(X+1,X+n,x)-X-1; 58 printf("%lld\n",ans[c]-1ll*c*x+1ll*(n-1-c)*x); 59 } 60 }