「NOI2015」寿司晚宴 解题报告

「NOI2015」寿司晚宴

这个题思路其实挺自然的,但是我太傻了...最开始想着钦定一些,结果发现假了..

首先一个比较套路的事情是状压前8个质数,后面的只会在一个数出现一次的再想办法就好。

然后发现有个重要的事情是后面每个质因子(x)做统计的时候都是独立的,那么单独做就好了

显然要压两个人的前面质因子集合(f_{i,j})代表两个人分别是(i,j)集合的答案,然后一块一块的加后面的质因子就好

加每一块时,我们显然需要处理谁选择了这一块或者都没选,再搞个(dp_{0/1,i,j})钦定一下谁选,随便转移一下就好了


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
template <class T>
void read(T &x)
{
	x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=510;
const int pri[9]={0,2,3,5,7,11,13,17,19};
int n,m,p,dp[2][1<<8][1<<8],f[1<<8][1<<8];
inline int add(int a,int b){return a+b>=p?a+b-p:a+b;}
inline int mul(int a,int b){return 1ll*a*b%p;}
struct num
{
	int s,pri;
	bool friend operator <(num a,num b){return a.pri<b.pri;}
}yuu[N];
int main()
{
	read(n),read(p);
	for(int i=2;i<=n;i++)
	{
		yuu[i].pri=i;
		for(int j=1;j<=8;j++)
			if(i%pri[j]==0)
			{
				yuu[i].s|=1<<j-1;
				while(yuu[i].pri%pri[j]==0) yuu[i].pri/=pri[j];
			}
	}
	std::sort(yuu+2,yuu+n+1);
	f[0][0]=1;int U=(1<<8)-1;
	for(int i=2;i<=n;i++)
	{
		if(yuu[i].pri!=yuu[i-1].pri||yuu[i].pri==1)
		{
			memcpy(dp[0],f,sizeof f);
			memcpy(dp[1],f,sizeof f);
		}
		int sta=yuu[i].s;
		for(int s=U;~s;s--)
			for(int t=U;~t;t--)
				if(!(s&t))
				{
					if(!(t&sta)) dp[0][s|sta][t]=add(dp[0][s|sta][t],dp[0][s][t]);
					if(!(s&sta)) dp[1][s][t|sta]=add(dp[1][s][t|sta],dp[1][s][t]);
				}
		if(yuu[i].pri!=yuu[i+1].pri||yuu[i].pri==1)
		{
			for(int s=0;s<=U;s++)
				for(int t=0;t<=U;t++)
					if(!(s&t))
						f[s][t]=add(add(dp[0][s][t],dp[1][s][t]),p-f[s][t]);
		}
	}
	int ans=0;
	for(int s=0;s<=U;s++)
		for(int t=0;t<=U;t++)
			ans=add(ans,f[s][t]);
	printf("%d
",ans);
	return 0;
}

2019.3.4

原文地址:https://www.cnblogs.com/butterflydew/p/10472085.html