40pts做法
互质实际上可以转化为对应数的质数集合不交.
所以我们可以用状态压缩的方法表示出一个数的质因子集合,定义 选出情况 的方案数.
背包+枚举子集.复杂度: (t表示质数的个数)
100pts
由于 ,所以第二大质因子 .
我们按最大质因子排序.
然后对于最大质因子 的我们暴力处理.
否则,我们对最大质因子相等的进行分段,同个段中的数只能由一个人选.
表示只能化为第一/二个人的选择的情况的方案.
复杂度 .
#include<bits/stdc++.h>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define fi first
#define se second
#define vi vector<int>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=510,M=1<<8|5,size=1<<20;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); puts("");
}
int n,p,s,g[N],h[N],prime[N],f[M][M],f1[M][M],f2[M][M];
bool v[N];
void upd(int &x) {x+=x>>31&p;}
pi a[N];
int main() {
qr(n); qr(p);
for(int i=2;i<=n;i++) {
if(!v[i]) h[i]=1<<min(s,8),prime[++s]=i,g[i]=i;
for(int j=1;i*prime[j]<=n;j++) {
v[i*prime[j]]=1;
g[i*prime[j]]=g[i];
h[i*prime[j]]=h[i]|h[prime[j]];
if(i%prime[j]==0) break;
}
a[i]=mk(g[i],i);
}
sort(a+2,a+n+1);
f[0][0]=1;
s=(1<<8)-1;
for(int r=2;r<=n;r++) {
bool flag=(a[r].fi!=a[r-1].fi||h[a[r].fi]<=s);
if(flag) {
memcpy(f1,f,sizeof f1);
memcpy(f2,f,sizeof f2);
}
int y=h[a[r].se]&s;
for(int i=s;i>=0;i--)
for(int j=s;j>=0;j--) if(!(i&j)) {
if(!(j&y)) upd(f1[i|y][j]+=f1[i][j]-p);
if(!(i&y)) upd(f2[i][j|y]+=f2[i][j]-p);
}
if(h[a[r].fi]<=s||a[r].fi!=a[r+1].fi)
for(int i=0;i<=s;i++)
for(int j=0;j<=s;j++)
upd(f[i][j]=(f1[i][j]+f2[i][j]-f[i][j])%p);
}
int ans=0;
for(int i=0;i<=s;i++)
for(int j=0;j<=s;j++)
upd(ans+=f[i][j]-p);
pr2(ans);
return 0;
}