Time:2016.06.29
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
比较巧妙的处理方法
关于互质这个问题很多都是出现在数论题目里
显然这个不是……
看到500这个数据范围,我首先想到的是网络流,咳咳……
好吧这也不是(用脚趾头都能想出来如果是网络流的话会让你求方案数+取模?)
500−−−√=22.36...
这个范围内的质数只有8个
似乎可以状压了吧……
也就是说,我们把两个人所吃的寿司看做是两个质数(实际上是质因子)的集合,一个人吃一个寿司就往这个人的集合里扔若干个质因子,只要这其中没有公共的质数就可以了
大于22的质数怎么办……
每个数最多只有一个大于22的质因子,拆解出来,排序分开计算了,把大于22的相同的质因子的数放到一起去
DP的方法也很巧妙……
类似背包那样做,避免重复计算
f=g+h-f
(因为g,h中各有一个之前的f值)
算了我还是先去食堂抢饭了
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,mo,ans;
int f[256][256],g[256][256],h[256][256],p[9]={0,2,3,5,7,11,13,17,19};
struct node{
int k,fac;
}a[502];
bool cmp(node a,node b){return a.k<b.k;}
void cal(node &x,int num)
{
for (int i=1;i<=8;i++)
if (num%p[i]==0)
{
x.fac|=1<<i-1;
while (num%p[i]==0) num/=p[i];
}
x.k=num;
}
main()
{
scanf("%d%d",&n,&mo);
for (int i=2;i<=n;i++)
cal(a[i],i);
sort(a+2,a+n+1,cmp);
f[0][0]=1;
for (int v=2;v<=n;v++)
{
if (a[v].k!=a[v-1].k||a[v].k==1)
for (int i=255;i>=0;i--)
for (int j=255;j>=0;j--)
if (!(i&j)) g[i][j]=h[i][j]=f[i][j];
for (int i=255;i>=0;i--)
for (int j=255;j>=0;j--)
if (!(i&j))
{
if (!(a[v].fac&j)) g[i|a[v].fac][j]=(g[i][j]+g[i|a[v].fac][j])%mo;
if (!(a[v].fac&i)) h[i][j|a[v].fac]=(h[i][j]+h[i][j|a[v].fac])%mo;
}
if (a[v].k!=a[v+1].k||a[v].k==1)
for (int i=255;i>=0;i--)
for (int j=255;j>=0;j--)
if (!(i&j)) f[i][j]=((g[i][j]+h[i][j])%mo-f[i][j])%mo;
}
for (int i=255;i>=0;i--)
for (int j=255;j>=0;j--)
if (!(i&j))
ans=(ans+f[i][j])%mo;
printf("%d",(ans%mo+mo)%mo);
}