【模拟赛】纪中提高A组 19.8.13 测试(数数场)

Posted on 2019-08-25 07:36  opethrax  阅读(132)  评论(0)    收藏  举报

良心的前置知识点普及时间:(如果都会就跳到Task.1)(赶工暂时先假装没有这个东西)

Task.1 Count

题目大意:求方程:\(\sum^k_{i=1}a_i=n\quad(\forall a_i\quad a_i\nmid m)\)有多少组不同的解。

数据范围:\(N\leq 10^{18},m\leq 5000,k\leq 2000\)

这是什么,这是被容斥支配的恐惧

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

template<class T>void read(T &x){
	x=0; char c=getchar();
	while(c<'0'||'9'<c)c=getchar();
	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
}
typedef unsigned long long ll;
const int N=5050;
const int M=998244353;
ll n,m,k;
int fac[N*N],inv[N*N],ifac[N*N];

ll C(ll x,ll y){
//	printf("%d %d\n",x,y);
	return x<y?0:1ll*fac[x]*ifac[y]%M*ifac[x-y]%M;
}
void init(){
	fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=1;
	for(int i=2;i<=k*(m-1);i++){
		fac[i]=1ll*fac[i-1]*i%M;
		inv[i]=1ll*inv[M%i]*(M-M/i)%M;
		ifac[i]=1ll*ifac[i-1]*inv[i]%M;
	}
}

int main(){
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	read(n); read(m); read(k);
	init();
	ll s=n%m,t;// if(s<k)s+=m;
	ll ans=0,sum,tmp,mul,rst;
	for(;s<=min(k*(m-1),n);s+=m){
		sum=C(s-1,k-1);
		for(ll i=1;i*(m-1)<=s;i++){
			t=s-i*(m-1);
			tmp=1ll*C(t-1,k-1)*C(k,i)%M;
			sum=i&1?(sum-tmp+M)%M:(sum+tmp)%M;
//			printf("%c %lld * %lld",i&1?'-':'+',C(t-1,k-1),C(i+k-1,k-1));
		}
//		printf("= %lld\n",sum);
		mul=ifac[k-1]; rst=(n-s)/m;
		for(ll i=rst+k-1;i>=rst+1;i--)mul=mul*(i%M)%M;
//		printf("%lld %lld %lld\n",s,sum,mul);
		sum=(sum*mul)%M;
		ans=(ans+sum)%M;
	}
	printf("%lld\n",ans);
	return 0;
}

Task.2 普及组

题目大意:定义一个 \(n\times n\) 的矩阵 \(A\) 是好的当它满足:\(\forall A_{i,j} \in \mathbb{Z},\ \forall j \prod^n_{i=1}A_{i,j}=x,\ \forall i \prod^n_{j=1}A_{j,i}=x\)。给出 \(n,x\),求有多少个好的矩阵。 \(T\) 组询问,对 \(998244353\) 取模。

数据范围:\(0\leq T\leq 2\times 10^5,1\leq n\leq 5\times 10^6\)

这个范围非常的“提答”,不得不贴:

我们非常套路的分解个质因数看看,发现这些个看着渗人的 \(x\) 的质因子的次幂都不超过 \(2\)

诶嘿嘿(我出去了)。

对于 \(x=1\) 的情况,

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

template<class T>void read(T &_){
	_=0; char c=getchar();
	while(c<'0'||'9'<c)c=getchar();
	while('0'<=c&&c<='9'){_=(_<<1)+(_<<3)+(c^48); c=getchar();}
}
typedef long long ll;
const int N=5000005;
const int M=998244353;
int fac[N],f[N],g[N];
int qpow(int a,int b){
	int tmp=1,base=a;
	while(b){
		if(b&1)tmp=(1ll*tmp*base)%M;
		base=(1ll*base*base)%M; b>>=1;
	} return tmp;
}

int main(){
	freopen("pj.in","r",stdin);
	freopen("pj.out","w",stdout);
	int cp,c1=0,c2=0,i2=499122177;
	ll x;
	int T,n,t;
	read(x); read(T);
	for(int p=2;1ll*p*p<=x;p++){
		if(x%p==0){
			cp=0; while(x/p*p==x)x/=p,++cp;
			(cp==1)?++c1:++c2;
		}
	} if(x>1)++c1;
	fac[0]=fac[1]=g[1]=1;
	for(int i=2;i<=5000000;i++){
		fac[i]=1ll*fac[i-1]*i%M;
		t=(f[i-1]+g[i-1]>=M)?(f[i-1]+g[i-1]-M):(f[i-1]+g[i-1]);
		g[i]=1ll*t*i%M;
		t=(t+f[i-1]>=M)?(t+f[i-1]-M):(t+f[i-1]);
		f[i]=1ll*t*i%M*(i-1)%M*i2%M;
	}
	while(T--){
		read(n); t=(f[n]+g[n]>=M)?(f[n]+g[n]-M):(f[n]+g[n]);
		printf("%d\n",1ll*qpow(fac[n],c1)*qpow(t,c2)%M*qpow(2,1ll*(n-1)*(n-1)%(M-1))%M);
	}
	return 0;
}

Task.3 提高组

题目大意:定义一个长度为 \(n\) 的正整数序列 \(A\) 是好的当:\(\forall A_i\ 1\leq A_i\leq n,\ i\neq j\Leftrightarrow A_i\neq A_j\),最长下降子序列长度不超过 \(2\)\(T\) 组询问,每次查询满足 \(A_x=y\) 的长度为 \(n\) 的好的序列有多少个,答案对 \(10^9+7\) 取模。

数据范围:\(0\leq T\leq 10^6,1\leq N\leq 10^7\)

题目那么长其实简单说就是求最长下降子序列长度不超过 \(2\) 的满足条件的排列有多少(害我打题目打这么久)

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

template<class T>void read(T &x){
	x=0; char c=getchar();
	while(c<'0'||'9'<c)c=getchar();
	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
}
const int N=20000005;
const int M=1000000007;
int fac[N],inv[N];
int qpow(int a,int b){int res=1;while(b){if(b&1)res=(1ll*res*a)%M; a=(1ll*a*a)%M; b>>=1;}return res;}
void init(){
	fac[0]=fac[1]=1;
	for(int i=2;i<=20000000;i++)
		fac[i]=(1ll*fac[i-1]*i)%M;
	inv[N-5]=qpow(fac[N-5],M-2);
	for(int i=N-5;i;i--)inv[i-1]=(1ll*inv[i]*i)%M;
}
int C(int n,int m){return (m>n)?0:1ll*fac[n]*inv[n-m]%M*inv[m]%M;}
int main(){
	freopen("tg.in","r",stdin);
	freopen("tg.out","w",stdout);
	int T,n,x,y; read(T); init();
	while(T--){
		read(n); read(x); read(y);
		if(x>y) swap(x,y);
		printf("%lld\n",1ll*(C(x+y-2,y-1)-C(x+y-2,y)+M)%M*(C(n*2-x-y,n-y)-C(n*2-x-y,n-y-1)+M)%M);
	}
	return 0;
}