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/