题意:
你有数值为
的
个数,你要把这些数分给两个人,可以有点数不分给任何人,每个人分到的数可以为空。分的时候如果第一个人分到的数存在一个数
,第二个人分到的数存在一个数
,使得
与
与共同的质因子,那么就不合法。也就是对于某一个质因子,它的所有倍数只可能分给同一个人。求有多少种合法的分配数的方案。
,
题解:
这个题在前两天学校的模拟赛中做过一个类似的题,当时也自己想出一个思路,当时没想好细节,就没写出来,但是那个题感觉比这个题要麻烦,于是这个题的思路就比较容易想了。
首先我们考虑数据范围小的情况,对于 的情况,我们可以直接把质因子状压一下,对于每个数,我们看一下它含哪些质因子,然后就用一个状压dp来算就可以了。我们设 表示第一个人选了 这个集合的质因子,第二个人选了 这个集合的质因子的方案数,然后转移就是 ,这里 就表示 这个数的所有质因子状压后的集合。
这个思路对于数据更大的情况的问题就是质因子太多,没法状压了。但是我们可以从另一个方面考虑,如果一个数含有一个大于 的质因子,那么这种质因子它最多含有一个,剩下的只可能还有一些小于 的质因子。于是我们考虑状压这些小于 的质因子,并对大的质因子特别处理一下。
我们的思路是,把含同一个大于 的质因子的数放在一起计算,这些数要么全都分给第一个人,要么全都分给第二个人。那么我们在新出现一个之前没算过的大于 的质因子的时候我们设 表示把含有这个质因子的数全分给第一个人,第一个人的集合是 ,第二个人的集合是 的方案数, 表示把含有这个质因子的数全分给第二个人,第一个人的集合是 ,第二个人的集合是 的方案数,这两个数组的初始值都是 的值。然后发现这个质因子结束的时候再更新 。此时的 ,原因是含这个大于 的质因子的所有数既没有给第一个人也没有给第二个人的方案数在 和 中各被算了一遍,重复计算了,所以我们要减去一遍,而应该减去的正好就是原来的这个没考虑这个大质因子时的 。剩下的就是简单状压dp处理了。最后答案就是把所有的KaTeX parse error: Expected 'EOF', got '&' at position 11: dp[i][j](i&̲j=0)的情况加起来。
这样的复杂度是 ,复杂度是 量级的,可以通过这个题。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,p[10],cnt=8,b[510],dp[1025][1025],f[1025][1025],g[1025][1025],mod,ans;
struct node
{
int s,val;
}a[1000];
inline int cmp(node x,node y)
{
return x.val<y.val;
}
int main()
{
scanf("%d%d",&n,&mod);
p[1]=2;
p[2]=3;
p[3]=5;
p[4]=7;
p[5]=11;
p[6]=13;
p[7]=17;
p[8]=19;
for(int i=1;i<=n-1;++i)
{
b[i]=i+1;
for(int j=1;j<=cnt;++j)
{
if(b[i]%p[j]==0)
{
a[i].s|=(1<<(j-1));
while(b[i]%p[j]==0)
b[i]/=p[j];
}
}
a[i].val=b[i];
}
sort(a+1,a+n,cmp);
dp[0][0]=1;
int mx=(1<<8)-1;
for(int i=1;i<=n-1;++i)
{
if(a[i].val==1||a[i].val!=a[i-1].val)
{
memcpy(f,dp,sizeof(dp));
memcpy(g,dp,sizeof(dp));
}
for(int j=mx;j>=0;--j)
{
for(int k=mx;k>=0;--k)
{
if(j&k)
continue;
if((a[i].s&k)==0)
f[j|a[i].s][k]=(f[j|a[i].s][k]+f[j][k])%mod;
if((a[i].s&j)==0)
g[j][k|a[i].s]=(g[j][k|a[i].s]+g[j][k])%mod;
}
}
if(a[i].val==1||a[i].val!=a[i+1].val||i==n-1)
{
for(int j=mx;j>=0;--j)
{
for(int k=mx;k>=0;--k)
{
if(j&k)
continue;
dp[j][k]=((f[j][k]+g[j][k])%mod-dp[j][k]+mod)%mod;
}
}
}
}
for(int i=0;i<=mx;++i)
{
for(int j=0;j<=mx;++j)
{
if(i&j)
continue;
ans=(ans+dp[i][j])%mod;
}
}
printf("%d\n",ans);
return 0;
}