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
*/