Luogu P2150 [NOI2015]寿司晚宴

题目

40pts做法

互质实际上可以转化为对应数的质数集合不交.

所以我们可以用状态压缩的方法表示出一个数的质因子集合,定义 f [ i ] f[i] 选出情况 i i 的方案数.

背包+枚举子集.复杂度: O ( n 2 t + 3 t ) O(n2^t+3^t) (t表示质数的个数)

100pts

由于 n 500 n\le 500 ,所以第二大质因子 22 \le 22 .

我们按最大质因子排序.

然后对于最大质因子 22 \le 22 的我们暴力处理.

否则,我们对最大质因子相等的进行分段,同个段中的数只能由一个人选.

f 1 , f 2 f1,f2 表示只能化为第一/二个人的选择的情况的方案.

复杂度 O ( 3 n n ) O(3^n n) .

#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;
}



猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106696066