luogu P3861 8月月赛A
题目描述
给定一个整数 n,求将 n 分解为互不相同的不小于 2 的数的乘积的方案数。答案模 998244353。
输入输出格式
输入格式:
第一行一个整数 T,表示数据组数。
接下来 T 行,每行一个整数 n,意义如描述所述。
输出格式:
一共 TT 行,每行一个整数,表示答案。
输入输出样例
说明
样例中,因为
688=2×4×86=2×8×43=2×344=4×172=8×86=16×43
所以答案为 66
对于 10% 的数据,保证 n 为质数
对于 20% 的数据,保证 2≤n≤104
对于 50% 的数据,保证 2≤n≤107
对于 100% 的数据, 保证 2≤n≤1012
所有数据满足 1≤T≤5
题目链接:https://www.luogu.org/problemnew/show/P3861
吐槽一下:
调了两小时的dp[吐血].
解题报告:
没有,下一个[吐血].
AC代码:
#include<cstdio> #include<algorithm> #include<cmath> #define FOR(i,s,t) for(register ll i=s;i<=t;++i) #define ll long long using namespace std; const ll MOD=998244353; ll T; ll cnt,pos,ans,q; ll n,tmp; ll a[1333333]; int pos1[1000011],pos2[1000011]; ll f[8111][8111]; inline void divide(){ cnt=0; q=sqrt(n); for(register ll i=1;i*i<=n;++i) if(n%(i*1ll)==0){ a[++cnt]=i,a[++cnt]=n*1ll/i; if(1ll*i*i==n)--cnt; } stable_sort(a+1,a+cnt+1); } inline void dp(){ FOR(i,0,cnt) FOR(j,0,cnt) f[i][j]=0; FOR(i,1,cnt){ ++f[i][i];//printf("%lld\n",a[i],i); a[i]<=q?pos1[a[i]]=i:pos2[(int)(n*1ll/a[i])]=i; } FOR(i,1,cnt) FOR(j,1,cnt){ f[i][j]=(f[i][j]+f[i][j-1])%MOD; if(i<=j)continue; if(a[i]%a[j]==0){ tmp=a[i]/a[j]; tmp<=q?f[i][j]+=f[pos1[tmp]][j-1]:f[i][j]+=f[pos2[(int)(n*1ll/tmp)]][j-1]; f[i][j]%=MOD; } } printf("%lld\n",f[cnt][cnt]-1); } int main(){ scanf("%lld",&T); while(T--){ scanf("%lld",&n); divide(); dp(); } return 0; }