【省選模擬】20/05/22

AA

  • 注意到如果可以不聯通的話方案數爲 2(n12)2^{\binom{n-1}{2}} 種,即考慮前面隨便連邊,最後一個點存在唯一一種合法的連邊方式,最後 lnln 或分治 nttnttn2n^2 容斥回去即可
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int> 
using namespace std;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 2e3 + 50;
int n, f[2][N], fc[N], ifc[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fc[n],mul(ifc[n-m],ifc[m])); }
void fc_init(int n){
	fc[0]=fc[1]=ifc[0]=ifc[1]=1;
	for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
	ifc[n]=ksm(fc[n],Mod-2);
	for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);
}
int main(){
	#ifdef FSYolanda
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout); 
	#endif
	scanf("%d",&n); fc_init(n); poly F(n+1,0); 
	for(int i=1; i<=n; i++) F[i]=ksm(2,(i-1)*(i-2)>>1);
	poly G = F;
	for(int i=1; i<=n; i++){
		for(int j=1; j<i; j++)
		Dec(F[i],mul(C(i-1,j-1),mul(F[j],G[i-j])));
	} cout<<mul(F[n],n*(n-1)>>1);
}

BB

  • 考慮跑一個從左上角開始的到關鍵格子的左上角的最短路樹,那麼這些最優路徑一定會包着這棵最短路樹,我們將格子的交點拆出 4 個點,直接連邊,考慮若最短路樹(綠色)穿過了兩個格點,那麼兩條黃色的邊將會被刪掉,再考慮需要圍一圈的限制,我們將關鍵格子藍色部分的點刪掉,這樣就可以保證從周圍繞過去,從左上角拆出來的右上角跑到左上角拆出來的左下角即走出了迴路,建出圖跑最短即可
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 代碼暫時咕掉了

CC

  • 看成一個長爲 mm 的序列,每種顏色的球爲 aia_i 個,帶標號,強制標號爲 1 的在最前方(除掉第一個放的),那麼答案就是合法的排列數
    若不考慮第一個不除,答案即爲
    m!ai\frac{m!}{\prod a_i}
    下面考慮第一個,首先第一個出現位置在其它球的第一個後方,我們對這個進行容斥,考慮點一個集合 SS 在當前枚舉的 tt 後方,那麼 tt 的貢獻是
    (1)Sat!(iSai+at1at1)(iSai)!iSai(miSai+at)(iS,itai)!iS,itai=(1)Sat2iai(iSai+at1)!m!(miSaiat)!(iSai+at)!(iS,itai)!=m!S(1)Sat2ai1iSai+at(-1)^{|S|}a_t!\binom{\sum_{i\in S}a_i+a_t-1}{a_t-1}*\frac{(\sum_{i\in S}a_i)!}{\prod_{i\in S}a_i}*\binom{m}{\sum_{i\in S}a_i+a_t}*\frac{(\sum_{i\notin S,i\neq t}a_i)!}{\prod_{i\notin S,i\neq t} a_i}\\ =(-1)^{|S|}\frac{a_t^2}{\prod_i a_i}(\sum_{i\in S}a_i+a_t-1)!\frac{m!}{(m-\sum_{i\in S}a_i-a_t)!(\sum_{i\in S}a_i+a_t)!}(\sum_{i\notin S,i\neq t}a_i)!\\=m!\sum_S(-1)^{|S|}\frac{a_t^2}{\prod a_i}\frac{1}{\sum_{i\in S}a_i+a_t}
    那麼我們只需要 dpdp
    fT=iSai=T,tS(1)Sf_T=\sum_{\sum_{i\in S}a_i=T,t\notin S}(-1)^{|S|}
    對於限制可以回退一下揹包,O(nm)O(nm),在膜拜了 ldxldx 之後即可分治 nttntt 做到 O(mlog2m)O(m\log^2m)
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int> 
using namespace std;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 55, M = 1e3 + 50;
int n, m, a[N], iv[M], fc[M], ifc[M];
int dp[M];
void fc_init(int n){
	fc[0]=fc[1]=ifc[0]=ifc[1]=iv[0]=iv[1]=1;
	for(int i=2; i<=n; i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);
	for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
	ifc[n]=ksm(fc[n],Mod-2);
	for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
//	freopen("comb.out","w",stdout);
	#endif
	scanf("%d",&n); int mt=1;
	for(int i=1; i<=n; i++) 
	scanf("%d",&a[i]), m+=a[i], Mul(mt,a[i]); 
	fc_init(m); mt=ksm(mt,Mod-2); 
	Mul(mt,fc[m]); dp[0]=1; 
	for(int i=1,S=0; i<=n; i++){
		S+=a[i]; for(int j=S; j>=a[i]; j--) 
		Dec(dp[j],dp[j-a[i]]);
	} int ans = 0;
	for(int i=1; i<=n; i++){
		for(int j=a[i]; j<=m; j++)
		Add(dp[j],dp[j-a[i]]); int Sum=0;
		for(int j=0; j<=m; j++) Add(Sum,mul(dp[j],iv[j+a[i]]));
		Add(ans, mul(a[i]*a[i],Sum));
		for(int j=m; j>=a[i]; j--)
		Dec(dp[j],dp[j-a[i]]);
	} cout << mul(ans,mt); return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章