2019.11.04【NOIP提高組】模擬 A&B 組(部分)

B組T4 JZOJ 1353 有趣的數列

題目

我們稱一個長度爲2n2n的數列是有趣的,當且僅當該數列滿足以下三個條件:
(1)它是從112n2n2n2n個整數的一個排列{ai}\{a_i\}
(2)所有的奇數項滿足a1<a3<<a2n1a_1<a_3<…<a_{2n-1},所有的偶數項滿足a2<a4<<a2na_2<a_4<…<a_{2n}
(3)任意相鄰的兩項a2i1a2i(1in)a_{2i-1}與a_{2i}(1≤i≤n)滿足奇數項小於偶數項,即:a2i1<a2ia_{2i-1}<a_{2i}
現在的任務是:對於給定的nn,請求出有多少個不同的長度爲2n2n的有趣的數列。因爲最後的答案可能很大,所以只要求輸出答案modP\bmod P的值。


分析

這道題目也就是在求C2nnn+1\frac{C_{2n}^n}{n+1},由於可能不存在逆元,所以分解質因數求答案


代碼

#include <cstdio>
#define rr register
using namespace std;
const int N=2e6+5;
int c[N],v[N],prime[N],lim,n,mod,ans=1,cnt;
inline void dfs(int x,int z){
	if (x==1) return;
	c[v[x]]+=z,dfs(x/v[x],z);
}
inline signed ksm(int x,int y){
	rr int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
signed main(){
	scanf("%d%d",&n,&mod),lim=2*n;
	for (rr int i=2;i<=lim;++i){
		if (!v[i]) v[i]=prime[++cnt]=i;
		for (rr int j=1;j<=cnt&&prime[j]*i<=lim;++j){
			v[i*prime[j]]=prime[j];
			if (i%prime[j]==0) break;
		}
	}
	for (rr int i=n+2;i<=2*n;++i) dfs(i,1);
	for (rr int i=2;i<=n;++i) dfs(i,-1);
	for (rr int i=2;i<=2*n;++i) ans=1ll*ans*ksm(i,c[i])%mod;
	return !printf("%d",ans);
} 

A組T1 JZOJ 6403 A

題目

在這裏插入圖片描述


分析

考慮容斥,即用總方案減去不合法的方案,若向xx軸正方向走XX步,向yy軸正方向走YY步,向zz軸正方向走ZZ步,記作doit(x,y,z)doit(x,y,z),那麼方案數也就是Cx+y+zz×Cx+yx=(x+y+z)!(x+y)!z!×(x+y)!x!y!=(x+y+z)!x!y!z!C_{x+y+z}^z\times C_{x+y}^x=\frac{(x+y+z)!}{(x+y)!z!}\times\frac{(x+y)!}{x!y!}=\frac{(x+y+z)!}{x!y!z!}
f[i]f[i]表示經過第ii個不可經過的點而沒有經過前i1i-1個不可經過的點的方案數
那麼f[i]=doit(xi,yi,zi)j=1i1f[j]doit(xixj,yiyj,zizj)f[i]=doit(x_i,y_i,z_i)-\sum_{j=1}^{i-1}f[j]doit(x_i-x_j,y_i-y_j,z_i-z_j)
特殊地,把終點也當做不可經過的點已統計最終答案,因爲座標必須遞增,所以先給不可經過的點升序排序,若這個不可經過的點無法到達下一個點,則不需轉移


代碼

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int mod=1e9+7,N=3e5+5,M=5e4+5;
struct rec{int x,y,z;}a[M];
int fac[N],inv[N],n,m,lim,dp[M];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
bool cmp(const rec &a,const rec &b){
	return a.x<b.x||(a.x==b.x&&(a.y<b.y||(a.y==b.y&&a.z<b.z)));
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed doit(int x,int y,int z){return 1ll*fac[x+y+z]*inv[x]%mod*inv[y]%mod*inv[z]%mod;}
signed main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	n=iut(),m=iut(),fac[0]=fac[1]=inv[0]=inv[1]=1,lim=3*n;
	for (rr int i=1;i<=m;++i) a[i].x=iut(),a[i].y=iut(),a[i].z=iut();
	for (rr int i=2;i<=lim;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod; a[++m]=(rec){n,n,n};
	for (rr int i=2;i<=lim;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
	sort(a+1,a+1+m,cmp);
	for (rr int i=1;i<=m;++i){
		dp[i]=doit(a[i].x,a[i].y,a[i].z);
		for (rr int j=1;j<i;++j){
			if (a[j].x>a[i].x||a[j].y>a[i].y||a[j].z>a[i].z) continue;
			dp[i]=mo(dp[i],mod-1ll*dp[j]*doit(a[i].x-a[j].x,a[i].y-a[j].y,a[i].z-a[j].z)%mod); 
		}
    }
    return !printf("%d",dp[m]);
}

A組T3 JZOJ 6405 C

題目

在這裏插入圖片描述


分析

根據一系列的找規律可以發現其實它在求i=1nj=1i(Cijim)2\sum_{i=1}^n\sum_{j=1}^i(C_i^ji^m)^2
=i=1ni2mj=1iCij2=\sum_{i=1}^ni^{2m}\sum_{j=1}^i{C_{i}^j}^2
然後後面這一坨等於C2iiC_{2i}^i
=i=1ni2mC2ii=\sum_{i=1}^ni^{2m}C_{2i}^i
所以O(n)O(n)求解


代碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=1e9+7,N=1e6+5;
int n,ans,fac[N<<1],jc[N],prime[N],cnt,m; bool v[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline signed ksm(int x,int y){
	rr int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans;
}
inline void pro(int lim){
    jc[0]=jc[1]=fac[0]=fac[1]=1;
    for (rr int i=2;i<=lim*2;++i) fac[i]=1ll*fac[i-1]*i%mod;
	for (rr int i=2;i<=lim;++i){
		if (!v[i]) prime[++cnt]=i,jc[i]=ksm(i,m);
		for (rr int j=1;j<=cnt&&prime[j]*i<=lim;++j){
			v[i*prime[j]]=1,jc[i*prime[j]]=1ll*jc[i]*jc[prime[j]]%mod;
			if (i%prime[j]==0) break;
		}
	}
}
signed main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	n=iut(),m=(iut()<<1)%(mod-1),pro(n);
	rr int inv=ksm(fac[n],mod-3);
	for (rr int i=n;i;--i){
		ans=mo(ans,1ll*jc[i]*mo(1ll*fac[i<<1]*inv%mod,mod-1)%mod);
		inv=1ll*inv*i%mod*i%mod;
	}
	return !printf("%d",ans); 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章