6210. wsm

询问有多少对序列\(A,B\),满足:\(|A|=m\),把所有\(A_i+B_j\)都丢进序列\(C\)中排序得到\(0,1,2,\dots,n-1\)

\(T\le 500,m|n\le 10^{12}\)


考虑暴力搜索的过程:

假设当前到达状态\(A=\{0,1\},B=\{0,2\}\)。此时已经表示了\(0\dots 3\),于是要添加\(4\)进去。

注意到因为\(\{0,1\}*\{0,2\}=\{0,1,2,3\}\),有\(\{0+4,1+4\}*\{0,2\}=\{4,5,6,7\}\),于是在\(A\)后面丢\(4,5\),变成\(\{0,1,4,5\}\)

当然也可以丢多一些,比如变成\(\{0,1,4,5,8,9,12,13\}\)。这相当于将\(\{0,1\}\)分开很多份,第\(k\)份加上\(4k\)

于是可以看成这样的过程:\(A,B\)轮流操作。假设当前的\(A,B\)能表示\(0\dots c-1\)。每次选择一个不为\(1\)的数\(d\),将当前序列复制\(d\)份(编号\(0\dots d-1\)),第\(k\)份总体加上\(kc\)

然后可以转化这样的问题:设\(F(n,m)=\sum_{1<d|n} F(m,\frac{n}{d})\)\(ans=F(m,\frac{n}{m})+F(\frac{n}{m},n)\)

接下来就简单多了:考虑计算\(F(n,m)\)。设\(f_n(c)\)表示对\(n\)做除法\(c\)次变成\(1\)的方案数。显然这可以分解质因数,容斥,对每个质因数分别计算得到。\(ans=\sum f_n(c)(f_m(c-1)+2f_m(c)+f_m(c+1))\)


using namespace std;
#include <bits/stdc++.h>
#define N 1000005
#define ll long long
#define mo 998244353
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
ll n,m;
int p[N],np;
bool inp[N];
void initp(int n=1000000){
	for (int i=2;i<=n;++i){
		if (!inp[i])
			p[++np]=i;
		for (int j=1;j<=np && i*p[j]<=n;++j){
			inp[i*p[j]]=1;
			if (i%p[j]==0)
				break;
		}
	}
}
const int K=105;
ll fac[K],ifac[K];
void initC(int n=100){
	fac[0]=1;
	for (int i=1;i<=n;++i)
		fac[i]=fac[i-1]*i%mo;
	ifac[n]=qpow(fac[n]);
	for (int i=n-1;i>=0;--i)
		ifac[i]=ifac[i+1]*(i+1)%mo;
}
ll C(int m,int n){return fac[m]*ifac[n]%mo*ifac[m-n]%mo;}
struct Query{
	ll n;
	ll d[K];
	int e[K],k,s;
	ll f[K];
	void work(ll _n){
		n=_n;
		ll t=n;
		k=0;
		for (int i=1;i<=np && t!=1;++i)
			if (t%p[i]==0){
				d[++k]=p[i],e[k]=0;
				while (t%p[i]==0)
					t/=p[i],e[k]++;
			}
		if (t!=1)
			d[++k]=t,e[k]=1;
		s=0;
		for (int i=1;i<=k;++i)
			s+=e[i];
		static ll g[N];
		g[0]=(n==1);
		for (int i=1;i<=s;++i){
			g[i]=1;
			for (int j=1;j<=k;++j)
				g[i]=g[i]*C(e[j]+i-1,i-1)%mo;
		}
		for (int i=0;i<=s;++i){
			f[i]=0;
			for (int j=0;j<=i;++j)
				(f[i]+=g[j]*C(i,j)*(i-j&1?-1:1))%=mo;	
			f[i]=(f[i]+mo)%mo;
		}
	}
	ll askf(int x){
		if (0<=x && x<=s)
			return f[x];
		return 0;
	}
} qn,qm;
int main(){
	freopen("wsm.in","r",stdin);
	freopen("wsm.out","w",stdout);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	initp();
	initC();
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%lld%lld",&n,&m);
		n/=m;
		if (n==1 || m==1){
			printf("1\n");
			continue;
		}
		qn.work(n);
		qm.work(m);
		ll ans=0;
		for (int i=0;i<=qn.s;++i)
			(ans+=qn.askf(i)*(qm.askf(i-1)+qm.askf(i)*2+qm.askf(i+1)))%=mo;
		printf("%lld\n",ans);
			
	}
	return 0;
}
posted @ 2021-04-26 20:24  jz_597  阅读(39)  评论(0编辑  收藏  举报