P5616 [MtOI2019]恶魔之树 题解

期望就是来搞笑的。

由于有最小公倍数,所以可以想到分解质因数,对于多个数求最小公倍数,取每个质因子的最大指数,最后相乘即可。

既然都知道了这个,那么就想到先统计每个数的个数,再将质因子作为状态,进行 dp。

但是由于 \(a_i\) 太大,无法装下所有的质因子,所以考虑根号分治。

对于质因子在 \(17\) 及以下的,存入状态中,对于在 \(17\) 以上的单独处理。

所以我们先把每个数分类,标准为多余质因子的大小(如果没有,那就为 \(1\))。

\(dp_{i,i_2,i_3,i_5,i_7,i_{11},i_{13},i_{17}}\) 为枚举到第 \(i\) 个数,最小公倍数为 \(2^{i_2}\times3^{i_3}\times5^{i_5}\times7^{i_7}\times11^{i_{11}}\times13^{i_{13}}\times17^{i_{17}}\)(不算多余质因子)的方案数。

那么:

\(dp_{i,\max(i_2,t_2),\max(i_3,t_3)......}=dp_{i,\max(i_2,t_2),\max(i_3,t_3)......}+dp_{i-1,i_2,i_3......}\)

其中 \(t_i\) 表示 \(n\) 的质因子 \(i\) 的指数个数。

由于其他因子的存在,所以我们需要建立第二个状态。

\(f_{i,i_2,i_3,i_5,i_7,i_{11},i_{13},i_{17},0/1}\) 代表枚举到第 \(i\) 个数,最小公倍数为 \(2^{i_2}\times3^{i_3}\times5^{i_5}\times7^{i_7}\times11^{i_{11}}\times13^{i_{13}}\times17^{i_{17}}\)(不算多余质因子),是否拥有多余因子的总和。

对于每一类多余因子的数,状态转移为:

\(f_{i,\max(t_2,i_2),\max(t_3,i_3)...... 1}=f_{i,\max(t_2,i_2),\max(t_3,i_3)...... 1}+f_{i-1,i_2,i_3......1}+tmp\times 2^{cnt_i-1}\)

\(f_{i,\max(t_2,i_2),\max(t_3,i_3)...... 1}=f_{i,\max(t_2,i_2),\max(t_3,i_3)...... 1}+f_{i-1,i_2,i_3......0}+tmp\times other\times 2^{cnt_i-1}\)

\(tmp\) 代表现最小公倍数除以原最小公倍数,即 \(2^{\max(i_2,t_2)-i_2}\times3^{\max(i_3,t_3)-i_3}......\)

\(cnt_i\) 代表数字 \(i\) 的个数,\(other\) 代表多余的因数。

初始值 \(f_{m,i_2,i_3......0}=2^{i_2}\times3^{i_3}......\times dp_{m,i_2,i_3......}\)

\(m\) 指第一个多余的因子不为 \(1\) 的数。

对于每一个多余的因子枚举完以后,要进行合并,即:

\(f_{i,i_2,i_3......0}=f_{i,i_2,i_3......0}+f_{i,i_2,i_3......1}\)

然后清空存在大因子的数组。

最后答案即为:\(\sum f_{n,i_2,i_3......0}\)。(\(n\) 指的是最后一个数)

空间开不下,利用滚动数组。

复杂度:\(O(n\times\log_2(n)\times\log_3(n)\times\log_5(n)\times\log_7(n)\times\log_{11}(n)\times\log_{13}(n)\times\log_{17}(n))\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=3e5+5;
const int M=305;
int n,cnt[M],mod=998244353,dp[2][9][6][4][3][3][3][3],f[2][9][6][4][3][3][3][3][2],p[20][N];
struct node
{
	int name,t[18],other;
}a[M];
int cmp(node fi,node se)
{
	if(fi.other==se.other)return fi.name<se.name;
	return fi.other<se.other;
}
inline int max(int x,int y)
{
	return x>y?x:y;
}
inline int quick_pow(int x,int y)
{
	if(p[x][y])return p[x][y];
	int sum=1,num=x,t=y;
	while(y)
	{
		if(y&1)sum*=num,sum%=mod;
		num*=num;
		num%=mod;
		y>>=1;
	}
	p[x][t]=sum;
	return sum;
}
void prepare()
{
	for(int i=1;i<=300;i++)
	{
		a[i].name=i;
		int x=i;
		for(int j=2;j*j<=i;j++)while(x%j==0)x/=j,a[i].t[j]++;
		if(x!=1&&x<=17)a[i].t[x]++,x=1;
		a[i].other=x;
	}
}
signed main()
{
	//freopen("easy25.in","r",stdin);
	//freopen("easy25.out","w",stdout); 
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%lld",&x);
		cnt[x]++;
	}
	prepare();
	sort(a+1,a+301,cmp);
	dp[0][0][0][0][0][0][0][0]=1;
	int cur=0;
	bool flag=1;
	for(int i=1;i<=300;i++)
	{
		if(i!=1&&a[i].other!=a[i-1].other)
		{
			if(flag)
			{
				flag=0;
				for(int i2=0;i2<=8;i2++)
				for(int i3=0;i3<=5;i3++)
				for(int i5=0;i5<=3;i5++)
				for(int i7=0;i7<=2;i7++)
				for(int i11=0;i11<=2;i11++)
				for(int i13=0;i13<=2;i13++)
				for(int i17=0;i17<=2;i17++)
				f[cur][i2][i3][i5][i7][i11][i13][i17][0]=
				dp[cur][i2][i3][i5][i7][i11][i13][i17]*
				quick_pow(2,i2)%mod*
				quick_pow(3,i3)%mod*
				quick_pow(5,i5)%mod*
				quick_pow(7,i7)%mod*
				quick_pow(11,i11)%mod*
				quick_pow(13,i13)%mod*
				quick_pow(17,i17)%mod;
			}
			else
			{
				for(int i2=0;i2<=8;i2++)
				for(int i3=0;i3<=5;i3++)
				for(int i5=0;i5<=3;i5++)
				for(int i7=0;i7<=2;i7++)
				for(int i11=0;i11<=2;i11++)
				for(int i13=0;i13<=2;i13++)
				for(int i17=0;i17<=2;i17++)
				f[cur][i2][i3][i5][i7][i11][i13][i17][0]+=f[cur][i2][i3][i5][i7][i11][i13][i17][1]
				,f[cur][i2][i3][i5][i7][i11][i13][i17][0]%=mod,
				f[cur][i2][i3][i5][i7][i11][i13][i17][1]=0;
			}
		}
		cur^=1;
		memcpy(dp[cur],dp[cur^1],sizeof(dp[cur^1]));
		for(int i2=0;i2<=8;i2++)
		for(int i3=0;i3<=5;i3++)
		for(int i5=0;i5<=3;i5++)
		for(int i7=0;i7<=2;i7++)
		for(int i11=0;i11<=2;i11++)
		for(int i13=0;i13<=2;i13++)
		for(int i17=0;i17<=2;i17++)
		{
			dp[cur][max(i2,a[i].t[2])]
			[max(i3,a[i].t[3])]
			[max(i5,a[i].t[5])]
			[max(i7,a[i].t[7])]
			[max(i11,a[i].t[11])]
			[max(i13,a[i].t[13])]
			[max(i17,a[i].t[17])]+=
			(dp[cur^1][i2][i3][i5][i7][i11][i13][i17]*(quick_pow(2,cnt[a[i].name])-1))%mod;
			dp[cur][max(i2,a[i].t[2])]
			[max(i3,a[i].t[3])]
			[max(i5,a[i].t[5])]
			[max(i7,a[i].t[7])]
			[max(i11,a[i].t[11])]
			[max(i13,a[i].t[13])]
			[max(i17,a[i].t[17])]%=mod;
		}
		//if(a[i].other==1)continue;
		//cout<<a[i].name<<" "<<f[0][0][0][0][0][0][0][0]<<" "<<cnt[a[i].name]<<endl;
		memcpy(f[cur],f[cur^1],sizeof(f[cur^1]));
		for(int i2=0;i2<=8;i2++)
		for(int i3=0;i3<=5;i3++)
		for(int i5=0;i5<=3;i5++)
		for(int i7=0;i7<=2;i7++)
		for(int i11=0;i11<=2;i11++)
		for(int i13=0;i13<=2;i13++)
		for(int i17=0;i17<=2;i17++)
		{
			int num=
			quick_pow(2,max(i2,a[i].t[2])-i2)%mod*
			quick_pow(3,max(i3,a[i].t[3])-i3)%mod*
			quick_pow(5,max(i5,a[i].t[5])-i5)%mod*
			quick_pow(7,max(i7,a[i].t[7])-i7)%mod*
			quick_pow(11,max(i11,a[i].t[11])-i11)%mod*
			quick_pow(13,max(i13,a[i].t[13])-i13)%mod*
			quick_pow(17,max(i17,a[i].t[17])-i17)%mod;
			f[cur][max(i2,a[i].t[2])]
			[max(i3,a[i].t[3])]
			[max(i5,a[i].t[5])]
			[max(i7,a[i].t[7])]
			[max(i11,a[i].t[11])]
			[max(i13,a[i].t[13])]
			[max(i17,a[i].t[17])][1]+=
			f[cur^1][i2][i3][i5][i7][i11][i13][i17][0]*num%mod
			*a[i].other%mod*(quick_pow(2,cnt[a[i].name])-1)%mod;
			f[cur][max(i2,a[i].t[2])]
			[max(i3,a[i].t[3])]
			[max(i5,a[i].t[5])]
			[max(i7,a[i].t[7])]
			[max(i11,a[i].t[11])]
			[max(i13,a[i].t[13])]
			[max(i17,a[i].t[17])][1]+=
			f[cur^1][i2][i3][i5][i7][i11][i13][i17][1]*num%mod
			*(quick_pow(2,cnt[a[i].name])-1)%mod;
		}
	}
	if(flag)
	{
		flag=0;
		for(int i2=0;i2<=8;i2++)
		for(int i3=0;i3<=5;i3++)
		for(int i5=0;i5<=3;i5++)
		for(int i7=0;i7<=2;i7++)
		for(int i11=0;i11<=2;i11++)
		for(int i13=0;i13<=2;i13++)
		for(int i17=0;i17<=2;i17++)
		f[cur][i2][i3][i5][i7][i11][i13][i17][0]=
		dp[cur][i2][i3][i5][i7][i11][i13][i17]*
		quick_pow(2,i2)%mod*
		quick_pow(3,i3)%mod*
		quick_pow(5,i5)%mod*
		quick_pow(7,i7)%mod*
		quick_pow(11,i11)%mod*
		quick_pow(13,i13)%mod*
		quick_pow(17,i17)%mod;
	}
	else
	{
		for(int i2=0;i2<=8;i2++)
		for(int i3=0;i3<=5;i3++)
		for(int i5=0;i5<=3;i5++)
		for(int i7=0;i7<=2;i7++)
		for(int i11=0;i11<=2;i11++)
		for(int i13=0;i13<=2;i13++)
		for(int i17=0;i17<=2;i17++)
		f[cur][i2][i3][i5][i7][i11][i13][i17][0]+=f[cur][i2][i3][i5][i7][i11][i13][i17][1]
		,f[cur][i2][i3][i5][i7][i11][i13][i17][0]%=mod,
		f[cur][i2][i3][i5][i7][i11][i13][i17][1]=0;
	}
	int ans=0;
	for(int i2=0;i2<=8;i2++)
	for(int i3=0;i3<=5;i3++)
	for(int i5=0;i5<=3;i5++)
	for(int i7=0;i7<=2;i7++)
	for(int i11=0;i11<=2;i11++)
	for(int i13=0;i13<=2;i13++)
	for(int i17=0;i17<=2;i17++)
	ans+=f[cur][i2][i3][i5][i7][i11][i13][i17][0],ans%=mod;
	printf("%lld",ans);
	return 0;
}
/*
10 1000000007
291 292 293 294 295 296 297 298 299 300
*/
posted @ 2023-02-24 13:39  Gmt丶Fu9ture  阅读(40)  评论(0)    收藏  举报