[NOI2015]寿司晚宴
题目描述
为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴。
小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴。
在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1,其中第种寿司的美味度为i+1(即寿司的美味度为从2到n)。
现在小G和小W希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:
小G品尝的寿司种类中存在一种美味度为x的寿司,小W品尝的寿司中存在一种美味度为y的寿司,而x与y不互质。
现在小G和小W希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数p取模)。
注意一个人可以不吃任何寿司
输入格式:
从文件dinner.in中读入数据。
输入文件的第1行包含2个正整数n,p中间用单个空格隔开,表示共有n种寿司,最终和谐的方案数要对p取模。
输出格式:
输出到文件dinner.out中。
输出一行包含1个整数,表示所求的方案模p的结果。
数据范围:
(30pt : 2 <= n <= 30)
(50pt : 2 <= n <= 100)
(70pt : 2 <= n <= 200)
(100pt : 2 <= n <= 500)
(p <= 1000000000)
嗯。。。。。。。。。怎么讲呢?虽然自己很快就想出来了,但是感觉自己还是很弱。
周六下午,一看这数据范围,(O(n^{3}))的(DP)
(dp(i,j,k))表示枚举到第(i)个数字,第(j)个质数,第(k)个。。。。。哪来的三个维???
突然想到大佬提起过状压。
还能压什么?压因子啊。
看了下500以内的素数个数:94个。。。。。。不现实啊
突然想到(sqrt{500}=22)内只有(2,3,5,7,11,13,17,19)这(8)个质数
(dp(i,S))表示枚举到数字(i),因子状态为(S)
复杂度(O(2^8*n))。。。。太小了吧。。。。。
不是两个集合吗?加一维:(dp(i,S1,S2))表示枚举到数字(i),第一个集合的因子状态(S1),第二个(S2)
嗯。。。。。。大于(sqrt{n})的怎么办???
放置了一会去想其他题目,突然懂了大于(sqrt{n})的因子不会在一个一个数中出现两次,因此可以把每个大因子集合单独拿出来(DP)
???做完了???其实思路是差不多完了。
进入正题:
对于第一维根本没有必要保持,可以去掉。
设(sta[i])表示(i)的因子状压出来的数字。
小因子转移方程:
(dp(S1|sta[i],S2)=dp(S1|sta[i],S2)+dp(S1,S2)(sta[i];and;S2==0))
(dp(S1,S2|sta[i])=dp(S1,S2|sta[i])+dp(S1,S2)(sta[i];and;S1==0))
而对于大因子,我们需要多开一维来记录大因子允许存在于第几个集合中
即(f(0/1,S1,S2))
转移方程:(以下转移条件同上,略去)
(f(0,S1|sta[i],S2)=f(0,S1|sta[i],S2)+f(0,S1,S2))
(f(1,S1|sta[i],S2)=f(1,S1|sta[i],S2)+f(1,S1,S2))
而最后合并的时候,因为两个(f)数组中都考虑了大因子不存在的情况,因此要减去一个,减什么?
还有什么没有考虑大因子呢?
自然是(dp(S1,S2))
大因子DP合并到小因子DP转移方程:
(dp(S1,S2)=f(0,S1,S2)+f(1,S1,S2)-dp(S1,S2))
最后答案即为:
(sum_{i=0}^{2^{8}-1} sum_{j=0}^{2^{8}-1} dp(i,j))
时间复杂度:(O(n*2^{16}))
补充:
模的是(10^{10})是(long;;long)范围的,不能开(int)
卡常代码,不建议仿生,可以选择参考其他人的