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.