题解 P5616 【[MtOI2019]恶魔之树】
可能更好的体验
发现
然后,
所以我们先不考虑那些大于
但是
注意只有
那么我们对
以下数组都忽略第一维的滚动维。
令
转移时枚举
接下来考虑大于
这里不能直接计算方案数,因为不知道最大质因子的出现情况。所以直接统计总贡献。
令
转移时,我们计算出新的最小公倍数与原来的最小公倍数差的那些因子的乘积
这个和上面的转移也是类似的。
我们处理完一个最大质因子后,需要把
那么总共的运算次数是
Code:
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#define rep(i,a,b)for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long LL;
//2:8 3:5 5:3 7:2 11:2 13:2 17:2
//4 3 2 2 2 2 2
int dp[2][9][6][4][3][3][3][3],F[2][2][9][6][4][3][3][3][3];
int n,md;
int cnt[305];
vector<pair<int,int> >vc[305];
vector<int>pc[305];
inline int pow(int a,int b){
int ret=1;
for(;b;b>>=1,a=(LL)a*a%md)if(b&1)ret=(LL)ret*a%md;
return ret;
}
void solve(int n,vector<pair<int,int> >&vec){
for(int i=2;i*i<=n;++i)if(n%i==0){
int cnt=0;
while(n%i==0)++cnt,n/=i;
vec.emplace_back(i,cnt);
}
if(n>1)vec.emplace_back(n,1);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>md;
for(int i=1;i<=n;++i){
int x;
cin>>x;
++cnt[x];
}
********dp=1;
int cur=0;
for(int i=1;i<=300;++i)if(cnt[i]){
solve(i,vc[i]);
if(i==1||vc[i].back().first<=17){
int fs=pow(2,cnt[i])-1;
cur^=1;
memcpy(dp[cur],dp[cur^1],sizeof*dp);
rep(a1,0,8)rep(a2,0,5)rep(a3,0,3)rep(a4,0,2)rep(a5,0,2)
rep(a6,0,2)rep(a7,0,2){
int s=dp[cur^1][a1][a2][a3][a4][a5][a6][a7];
if(!s)continue;
int b1=0,b2=0,b3=0,b4=0,b5=0,b6=0,b7=0;
for(auto j:vc[i]){
switch(j.first){
case 2:b1=j.second;break;
case 3:b2=j.second;break;
case 5:b3=j.second;break;
case 7:b4=j.second;break;
case 11:b5=j.second;break;
case 13:b6=j.second;break;
case 17:b7=j.second;break;
}
}
b1=max(b1,a1);
b2=max(b2,a2);
b3=max(b3,a3);
b4=max(b4,a4);
b5=max(b5,a5);
b6=max(b6,a6);
b7=max(b7,a7);
int t=pow(2,b1)*pow(3,b2)%md*pow(5,b3)%md*pow(7,b4)%md*pow(11,b5)%md*pow(13,b6)%md
*pow(17,b7)%md;
int&to=dp[cur][b1][b2][b3][b4][b5][b6][b7];
to=(to+(LL)s*fs)%md;
}
}else
pc[vc[i].back().first].push_back(i);
}
int ans=0;
rep(a1,0,8)rep(a2,0,5)rep(a3,0,3)rep(a4,0,2)rep(a5,0,2)
rep(a6,0,2)rep(a7,0,2)
F[0][0][a1][a2][a3][a4][a5][a6][a7]=dp[cur][a1][a2][a3][a4][a5][a6][a7]*((LL)
pow(2,a1)*pow(3,a2)%md*pow(5,a3)%md*pow(7,a4)%md*pow(11,a5)%md*pow(13,a6)%md
*pow(17,a7)%md)%md;
cur=0;
for(int p=2;p<=300;++p){
for(int i:pc[p]){
int fs=pow(2,cnt[i])-1;
cur^=1;
memcpy(F[cur],F[cur^1],sizeof*F);
rep(ff,0,1)rep(a1,0,8)rep(a2,0,5)rep(a3,0,3)rep(a4,0,2)rep(a5,0,2)
rep(a6,0,2)rep(a7,0,2){
int s=F[cur^1][ff][a1][a2][a3][a4][a5][a6][a7];
if(!s)continue;
int b1=0,b2=0,b3=0,b4=0,b5=0,b6=0,b7=0;
for(auto j:vc[i]){
switch(j.first){
case 2:b1=j.second;break;
case 3:b2=j.second;break;
case 5:b3=j.second;break;
case 7:b4=j.second;break;
case 11:b5=j.second;break;
case 13:b6=j.second;break;
case 17:b7=j.second;break;
}
}
int dlt=
pow(2,max(b1-a1,0))*
pow(3,max(b2-a2,0))%md*
pow(5,max(b3-a3,0))%md*
pow(7,max(b4-a4,0))%md*
pow(11,max(b5-a5,0))%md*
pow(13,max(b6-a6,0))%md*
pow(17,max(b7-a7,0))%md*pow(p,ff^1)%md;
b1=max(b1,a1);
b2=max(b2,a2);
b3=max(b3,a3);
b4=max(b4,a4);
b5=max(b5,a5);
b6=max(b6,a6);
b7=max(b7,a7);
int&to=F[cur][1][b1][b2][b3][b4][b5][b6][b7];
to=(to+s*(LL)dlt%md*fs)%md;
}
}
rep(a1,0,8)rep(a2,0,5)rep(a3,0,3)rep(a4,0,2)rep(a5,0,2)
rep(a6,0,2)rep(a7,0,2){
int&f=F[cur][0][a1][a2][a3][a4][a5][a6][a7];
int&g=F[cur][1][a1][a2][a3][a4][a5][a6][a7];
f=(f+g)%md;
g=0;
}
}
rep(a1,0,8)rep(a2,0,5)rep(a3,0,3)rep(a4,0,2)rep(a5,0,2)
rep(a6,0,2)rep(a7,0,2)
ans=(ans+F[cur][0][a1][a2][a3][a4][a5][a6][a7])%md;
cout<<ans<<endl;
return 0;
}