CF893E Counting Arrays 题解

分析

为了方便起见,用 \(n\) 代替 \(x\)\(m\) 代替 \(y\)

不难发现无论 \([1,m-1]\) 这些数字的符号是什么样的,只要恰当安排最后一位就一定能使结果是正数。由于每一位正负都可以选,所以这部分的方案数为 \(2^{m-1}\)

考虑到值域不大,可以单独考虑每个质因子。

对于一个质因子 \(p_i\),它的次数为 \(a_i\)。问题转化为在 \([1,m]\)\(m\) 个位置中,每个位置分配一个数,分配的数之和等于 \(a_i\),求方案数。形式化地,求不定方程 \[ \sum_{i=1}^m x_i = a_i \] 的非负整数解的个数,显然是 \(\binom{m+a_i-1}{a_i-1}\)。累乘即可。

线性筛预处理质数,分解质因数时只枚举质数的复杂度是 \(O(\log_2n)\) 的,并且常数较小。

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e6+5, mod=1e9+7;
int t, n, m, cnt, ans, fac[N], inv[N], p2[N], p[N], v[N];
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
int fp(int x,int y) {
	int z=1; x%=mod;
	for(;y;x=x*x%mod,y>>=1) if(y&1) z=z*x%mod;
	return z;
}

int C(int n,int m) {
	return n<=m? 1:fac[n]*inv[m]%mod*inv[n-m]%mod; 
}
void ora() {
	for(int i=2;i<=2e6;++i) {
		if(!v[i]) p[++cnt]=i;
		for(int j=1;j<=cnt&&i*p[j]<=2e6;++j) {
			v[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
}
void init() {
	fac[1]=1, inv[0]=1, p2[0]=1, p2[1]=2;
	for(int i=2;i<=2e6;++i) fac[i]=fac[i-1]*i%mod, p2[i]=p2[i-1]*2%mod;
	inv[N-5]=fp(fac[N-5],mod-2);
	for(int i=(2e6)-1;i;--i) inv[i]=inv[i+1]*(i+1)%mod;
	ora();
}
void solve() {
	n=read(), m=read();
	ans=p2[m-1];
	for(int i=1;p[i]*p[i]<=n;++i) {
		if(n%p[i]) continue;
		int a=0;
		while(!(n%p[i])) ++a, n/=p[i];
		(ans*=C(m+a-1,m-1))%=mod;
	}
	if(n>1) (ans*=m)%=mod; 
	printf("%lld\n",ans);
}
signed main() {
	init();
    scanf("%d",&t);
    while(t--) solve();
}

CF893E Counting Arrays 题解
https://yozora0908.github.io/2022/cf893e-solution/
作者
yozora0908
发布于
2022年7月31日
许可协议