标签:包括 include 解决 style i+1 -- std 策略 通过
题目描述
输入
输出
样例输入
4 0
0 0 1 1
样例输出
512
题解
数论+期望dp,考场上唯一A了的一道题
首先解决正常游戏的操作次数。
易知每个开关都不能被其它的开关组所替代,且每个开关只会影响它和编号比它小的灯。
于是可以从大到小循环一遍,如果一个灯是亮着的,那么把它关闭,把它约数的状态反转,并把num++。
即最终有num个正确选择。
然后解决期望次数。
设b[i]表示从有i个正确选择变为有i-1个正确选择的期望操作次数。
那么可以推出b[i]=i/n*1+(1-i/n)*(1+b[i+1]+b[i]),即b[i]=(b[i+1]*(n-i)+n)/i。
特殊的,b[n+1]=0
然后就可以推出b数组,再判断一下num与k的大小关系并累加一下,最后乘一下n!即可。
考场源代码:
#include <cstdio> #define mod 100003 typedef long long ll; int v[100010]; ll b[100010]; ll qpow(ll x , ll y) { ll ans = 1; while(y) { if(y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1; } return ans; } int main() { int n , k , i , j , num = 0; ll t = 0; scanf("%d%d" , &n , &k); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]); for(i = n ; i >= 1 ; i -- ) { if(v[i]) { for(j = 1 ; j * j <= i ; j ++ ) { if(i % j == 0) { v[j] ^= 1; if(j * j != i) v[i / j] ^= 1; } } num ++ ; } } for(i = n ; i >= 1 ; i -- ) b[i] = (b[i + 1] * (n - i) % mod + n) % mod * qpow(i , mod - 2) % mod; if(n == k || k > num) t = num; else { for(i = num ; i > k ; i -- ) t = (t + b[i]) % mod; t = (t + k) % mod; } for(i = 1 ; i <= n ; i ++ ) t = t * i % mod; printf("%lld\n" , t); return 0; }
【bzoj4872】[Shoi2017]分手是祝愿 数论+期望dp
标签:包括 include 解决 style i+1 -- std 策略 通过
原文地址:http://www.cnblogs.com/GXZlegend/p/6764969.html