luogu P3861 8月月赛A

题目描述

给定一个整数 n,求将 n 分解为互不相同的不小于 2 的数的乘积的方案数。答案模 998244353

输入输出格式

输入格式:

 

第一行一个整数 T,表示数据组数。

接下来 T 行,每行一个整数 n,意义如描述所述。

 

输出格式:

 

一共 TT 行,每行一个整数,表示答案。

 

输入输出样例

输入样例#1: 复制
1
688
输出样例#1: 复制
6

说明

样例中,因为

688=2×4×86=2×8×43=2×344=4×172=8×86=16×43

所以答案为 66

对于 10% 的数据,保证 n 为质数

对于 20% 的数据,保证 2n104

对于 50% 的数据,保证 2n107

对于 100% 的数据, 保证 2n1012

所有数据满足 1T5

题目链接: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;
}

  

posted @ 2017-11-04 22:28  Stump  阅读(193)  评论(0编辑  收藏  举报