ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【洛谷P2150】[NOI2015] 寿司晚宴

2021-10-30 20:02:54  阅读:152  来源: 互联网

标签:f1 f2 洛谷 P2150 int NOI2015 DP dp mod


前言

【题目传送门】
本题之前在 \(lyn\) 大佬讲课的时候讲过,但当时没怎么听懂,只记得是分解质因数然后状压。

题解

设计 DP

从状压入手。
首先考虑朴素 DP。
一开始我想到设计一维 \(dp_{stat}\) 表示一个人拿的数字的质因子集合,从此可以推出另一个人可以选择的物品。但是这样转移的时候不知道哪些物品是否被选,实际上也就不能推出另一个人可以选择的物品
这样不行那就再加一维,记 \(dp(i,j)\) 表示小 G,小 W 选的质因子集合分别为 \(i,j\)。本来还应该有一维记录当前选到第几个数字,但是通过倒序枚举就可以滚动数组优化掉。

优化 DP

上面的方法适用于质因子数量较少的情况,而当 \(n=500\) 时有 \(100\) 个左右的质数。
考虑状压本质,其实就是为了防止两个集合有交集。发现 \(500\) 以下的数字最大的质因子如果不小于 \(22\),最多只有一个。所以单独记录一维表示是否有大质因子。
具体实现上,把大质因子相同的数字排列成一段,用两个定义和 \(dp\) 数组相同的辅助数组 \(f1,f2\) 分别转移两个人选择包含当前这个大质因子的数(同一段的数字要选只能一个人选),这样也不用给原本的 DP 加维了,每段结束的时候把 \(f1,f2\) 的值传递给 \(dp\) 数组即可。

一点问题

关于一些边界的判断和细节也要格外小心,即使是看了题解也没有一次过。

  • 转移 DP 出现减法的时候没有加模数。
  • 转移 \(f1,f2\) 数组判断的时候正好判断反了。应该是另一个当前选的数字和另一个集合没有交集。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 505;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
ll n,mod;
ll dp[256][256],f1[256][256],f2[256][256];
const int p[10]={0,2,3,5,7,11,13,17,19};
struct node 
{
	int pig,stat,num;
	inline bool operator < (const node &oth)const {return pig<oth.pig;}
	void init()
	{
		int tmp=num;
		for(int i=1;i<=8;i++)	
			if(tmp%p[i]==0) 
			{
				stat|=1<<(i-1);
				while(!(tmp%p[i])) tmp/=p[i];
			}
		if(tmp!=1) pig=tmp;
	}
}a[N];
inline void trans(int now)
{
	if(a[now].pig!=a[now-1].pig||!a[now].pig||now==1)
		for(int i=0;i<256;i++)	
			for(int j=0;j<256;j++)	
				f1[i][j]=f2[i][j]=dp[i][j];
	return;
}
int main()
{
	n=read(),mod=read();
	for(int i=1;i<=n-1;i++) a[i].num=i+1,a[i].init();
	sort(a+1,a+n+1);
	dp[0][0]=1LL;  
	for(int i=1;i<=n-1;i++)	
	{
		trans(i);//这一段大质因数开始的时候赋值 
		for(int j=255;j>=0;j--)
			for(int k=255;k>=0;k--)
			{//滚动数组,倒序枚举 
				if(j&k) continue;
				if(!(k&a[i].stat)) (f1[j|a[i].stat][k]+=f1[j][k])%=mod;
				if(!(j&a[i].stat)) (f2[j][k|a[i].stat]+=f2[j][k])%=mod;
			}
		if(a[i].pig!=a[i+1].pig||!a[i].pig||i==n-1)//这一段大质因数结束的时候更新dp 
		for(int j=255;j>=0;j--)
			for(int k=255;k>=0;k--)
			{
				if(j&k) continue;
				dp[j][k]=f1[j][k]+f2[j][k]-dp[j][k]+mod;//减法+mod 
				dp[j][k]%=mod;
			}
	}
	ll ans=0ll;
	for(int i=0;i<256;i++)	
		for(int j=0;j<256;j++)	
		{
			if(i&j) continue;
			ans+=dp[i][j],ans%=mod;
		}
	printf("%lld\n",ans);
	return 0;
}

标签:f1,f2,洛谷,P2150,int,NOI2015,DP,dp,mod
来源: https://www.cnblogs.com/conprour/p/15487070.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有