BZOJ4197:[NOI2015]寿司晚宴

Description

为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴。小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴。
在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 1,2,3,…,n−1,其中第 i 种寿司的美味度为 i+1 (即寿司的美味度为从 2 到 n)。
现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y 的寿司,而 x 与 y 不互质。
现在小 G 和小 W 希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数 p 取模)。注意一个人可以不吃任何寿司。

Input

输入文件的第 1 行包含 2 个正整数 n,p,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。

Output

输出一行包含 1 个整数,表示所求的方案模 p 的结果。 

Sample Input

3 10000

Sample Output

9

HINT

2≤n≤500

0<p≤1000000000
 
题解:
两人拥有的寿司美味度的质因子数不能有重复,对于小于√500的质因子将其在G手中、在W手中、不在两人手中压缩成3进制状态j,用dp[j]储存方案数。
先预处理好美味度为小于√500的质数的寿司归属,在枚举其他寿司插入。
插入一个大于√500的质数寿司P时,同时考虑其倍数。新开一个数组dp2[0~2,j]表示该质因子不在二人手中、在G手中、在W手中时,状态为j的方案数
将P的倍数寿司插入,假设其为KP,通过三个数组转移。
注意转移时该质因子归属、小于√500质因子归属的变化(若K的某个质因子p已在对方手中,则不可拥有;若两人都不拥有,则可以拥有这个寿司,并更新状态;若p质因子已在自己手中,则可以拥有这个寿司)
转移方向:0——>1、2   1——>1   2——>2
用所有P的倍数插入并转移后,将dp2[1~2]数组转到dp数组中。
插入质因子都在√500以内的合数寿司时,用类似方法在DP数组中转移。
最后统计答案。
 
代码:
 1 uses math;
 2 const
 3   zs:array[1..8]of longint=(2,3,5,7,11,13,17,19);
 4 var
 5   i,ii,j,jj,k,l,fl,n:longint;
 6   a:array[0..501]of int64;
 7   b:array[0..8]of int64;
 8   dp:array[0..7000]of int64;
 9   dp2:array[0..2,0..7000]of int64;
10   ans,tj,mo:int64;
11 begin
12   readln(n,mo);
13   b[0]:=1; for i:=1 to 8 do b[i]:=b[i-1]*3;
14   for i:=0 to b[8]-1 do dp[i]:=1;
15   for i:=2 to n do
16   if a[i]=0 then
17   begin
18     j:=i*2;
19     while j<=n do
20     begin
21       if i>20 then a[j]:=2 else a[j]:=max(a[j],1);
22       j:=j+i;
23     end;
24     if i>20 then
25     begin
26       for j:=0 to b[8]-1 do
27       begin
28         dp2[0,j]:=dp[j]; dp2[1,j]:=0; dp2[2,j]:=0;
29       end;
30       ii:=i; k:=1;
31       while ii<=n do
32       begin
33         for jj:=1 to 2 do
34         for j:=b[8]-1 downto 0 do
35         if dp2[jj,j]>0 then
36         begin
37           tj:=j; fl:=0;
38           for l:=1 to 8 do
39           if k mod zs[l]=0 then
40           begin
41             if (tj div b[l-1])mod 3=3-jj then
42             begin fl:=1; break; end else
43             tj:=tj+(jj-(tj div b[l-1])mod 3)*b[l-1];
44           end;
45           if fl=0 then dp2[jj,tj]:=(dp2[jj,tj]+dp2[jj,j])mod mo;
46         end;
47         for j:=b[8]-1 downto 0 do
48         begin
49           for jj:=1 to 2 do
50           begin
51             tj:=j; fl:=0;
52             for l:=1 to 8 do
53             if k mod zs[l]=0 then
54             begin
55               if (tj div b[l-1])mod 3=3-jj then
56               begin fl:=1; break; end else
57               tj:=tj+(jj-(tj div b[l-1])mod 3)*b[l-1];
58             end;
59             if fl=0 then dp2[jj,tj]:=(dp2[jj,tj]+dp2[0,j])mod mo;
60           end;
61         end;
62         ii:=ii+i; inc(k);
63       end;
64       for j:=0 to b[8]-1 do dp[j]:=(dp[j]+dp2[1,j]+dp2[2,j])mod mo;
65     end;
66   end else
67   if a[i]=1 then
68   begin
69     for j:=b[8]-1 downto 0 do
70     begin
71       for jj:=1 to 2 do
72       begin
73         tj:=j; fl:=0;
74         for l:=1 to 8 do
75         if i mod zs[l]=0 then
76         begin
77           if (tj div b[l-1])mod 3=3-jj then
78           begin fl:=1; break; end else
79           tj:=tj+(jj-(tj div b[l-1])mod 3)*b[l-1];
80         end;
81         if fl=0 then dp[tj]:=(dp[tj]+dp[j])mod mo;
82       end;
83     end;
84   end;
85   for i:=0 to b[8]-1 do
86   begin
87     fl:=0;
88     for l:=1 to 8 do
89     if(zs[l]>n)and((i div b[l-1])mod 3<>0)then
90     begin fl:=1; break; end;
91     if fl=0 then ans:=(ans+dp[i])mod mo;
92   end;
93   writeln(ans);
94 end.
View Code
posted @ 2017-01-07 20:59  GhoStreach  阅读(156)  评论(0编辑  收藏  举报