【BZOJ4872】分手是祝愿(期望DP)
题意:
B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态,下标为
从 1 到 n 的正整数。每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,游戏
的目标是使所有灯都灭掉。但是当操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被
改变,即从亮变成灭,或者是从灭变成亮。B 君发现这个游戏很难,于是想到了这样的一个策略,每次等概率随机
操作一个开关,直到所有灯都灭掉。这个策略需要的操作次数很多, B 君想到这样的一个优化。如果当前局面,
可以通过操作小于等于 k 个开关使所有灯都灭掉,那么他将不再随机,直接选择操作次数最小的操作方法(这个
策略显然小于等于 k 步)操作这些开关。B 君想知道按照这个策略(也就是先随机操作,最后小于等于 k 步,使
用操作次数最小的操作方法)的操作次数的期望。这个期望可能很大,但是 B 君发现这个期望乘以 n 的阶乘一定
是整数,所以他只需要知道这个整数对 100003 取模之后的结果。
1 ≤ n ≤ 100000, 0 ≤ k ≤ n;
思路:更正:下图中g[i]=((n-i)*g[i+1]+n)/i,官方题解谋财害命
我不是很了解最后一张图在说什么
1 const mo=100003; 2 var head,a:array[1..200000]of longint; 3 vet,next:array[1..5000000]of longint; 4 exf,f,g:array[0..200000]of int64; 5 n,k1,i,j,t,e,v,tot:longint; 6 s,ans:int64; 7 8 procedure add(a,b:longint); 9 begin 10 inc(tot); 11 next[tot]:=head[a]; 12 vet[tot]:=b; 13 head[a]:=tot; 14 end; 15 16 function mult(x,y:int64):int64; 17 begin 18 mult:=1; 19 while y>0 do 20 begin 21 if y and 1=1 then mult:=mult*x mod mo; 22 x:=x*x mod mo; 23 y:=y>>1; 24 end; 25 end; 26 27 begin 28 assign(input,'bzoj4872.in'); reset(input); 29 assign(output,'bzoj4872.out'); rewrite(output); 30 readln(n,k1); 31 exf[0]:=1; exf[1]:=1; 32 for i:=2 to 100003 do exf[i]:=exf[mo mod i]*(mo-mo div i) mod mo; 33 for i:=1 to n do read(a[i]); 34 for i:=1 to n do 35 for j:=1 to n div i do 36 begin 37 t:=j*i; 38 add(t,i); 39 end; 40 for i:=n downto 1 do 41 if a[i]=1 then 42 begin 43 inc(s); 44 e:=head[i]; 45 while e<>0 do 46 begin 47 v:=vet[e]; 48 a[v]:=a[v] xor 1; 49 e:=next[e]; 50 end; 51 end; 52 if s<=k1 then 53 begin 54 for i:=1 to n do s:=s*i mod mo; 55 writeln(s); 56 close(input); 57 close(output); 58 exit; 59 end; 60 g[n]:=1; 61 for i:=n-1 downto k1+1 do 62 g[i]:=(g[i+1]*(n-i) mod mo+n) mod mo*exf[i] mod mo; 63 for i:=1 to k1 do g[i]:=1; 64 for i:=0 to k1 do f[i]:=i; 65 for i:=k1+1 to n do f[i]:=(f[i-1]+g[i]) mod mo; 66 ans:=f[s]; 67 for i:=1 to n do ans:=ans*i mod mo; 68 writeln(ans); 69 close(input); 70 close(output); 71 end.
null