博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj4872】[Shoi2017]分手是祝愿 期望dp
阅读量:5290 次
发布时间:2019-06-14

本文共 2099 字,大约阅读时间需要 6 分钟。

Description

Zeit und Raum trennen dich und mich.

时空将你我分开。B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态,下标为

从 1 到 n 的正整数。每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,游戏

的目标是使所有灯都灭掉。但是当操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被

改变,即从亮变成灭,或者是从灭变成亮。B 君发现这个游戏很难,于是想到了这样的一个策略,每次等概率随机

操作一个开关,直到所有灯都灭掉。这个策略需要的操作次数很多, B 君想到这样的一个优化。如果当前局面,

可以通过操作小于等于 k 个开关使所有灯都灭掉,那么他将不再随机,直接选择操作次数最小的操作方法(这个

策略显然小于等于 k 步)操作这些开关。B 君想知道按照这个策略(也就是先随机操作,最后小于等于 k 步,使

用操作次数最小的操作方法)的操作次数的期望。这个期望可能很大,但是 B 君发现这个期望乘以 n 的阶乘一定

是整数,所以他只需要知道这个整数对 100003 取模之后的结果。

Input

第一行两个整数 n, k。

接下来一行 n 个整数,每个整数是 0 或者 1,其中第 i 个整数表示第 i 个灯的初始情况。

1 ≤ n ≤ 100000, 0 ≤ k ≤ n;

Output

输出一行,为操作次数的期望乘以 n 的阶乘对 100003 取模之后的结果。

Sample Input

4 0

0 0 1 1

Sample Output

512

Sol

作为一道联考省选题,覆盖知识点广,题目又着切合实际的背景,解法比较自然,给出题人点赞!

题确实挺好的,但是我太菜了模拟赛的时候直接模拟骗了80分......后来听了讲解才补的......

我们发现每个灯只用按一次,而每个灯的贡献又是独一无二的,所以需要按的灯的集合是固定的,每次我们只关心按的灯对于剩余步数的贡献,设\(f[i]\)表示还需要i步才能全部按灭的期望步数,则\(f[i]=\frac{i}{n}f[i-1]+\frac{n-i}{n}f[i+1]+1\),也就是分两种情况:按的灯在不在有用集合里面。

这个式子并不需要高斯消元,有两种做法:

1.因为f[0]是确定的,所以可以用回代法求出所有的值,时间复杂度\(O(n)\)

2.设\(g[i]=f[i]-f[i-1]\),表示从需要i步到需要i-1步的期望次数,那么:

\(f[i]-\frac{i}{n}f[i-1]=\frac{n-i}{n}f[i+1]+1\)

\(f[i]-f[i-1]=\frac{n-i}{n}(f[i+1]-f[i-1])+1\)

\(g[i]=\frac{n-i}{i}((f[i+1]-f[i])+(f[i]-f[i-1]))+1\)

\(g[i]=\frac{n-i}{i}(g[i+1]+g[i])+1\)

\(\frac{i}{n}g[i]=1+\frac{n-i}{n}g[i+1]\)

\(g[i]=\frac{n+(n-i)g[i+1]}{i}\)

然后就可以\(O(n)\)计算了。

算出来以后特判一下\(n=k\)以及\(k>=tot\)的情况(tot为有用的灯集合大小),这样的情况下答案直接是tot。

否则答案\(=(\sum_{i=k+1}^{tot}g[i])+k\)

Code

#include 
using namespace std;int n,a[100005],f[100005],tot,K,fac=1,P=100003,ans;vector
e[100005];int ksm(int a,int b){int res=1;for(;b;b>>=1,a=1ll*a*a%P) if(b&1) res=1ll*res*a%P;return res;}int main(){ for(int i=1;i<=P-3;i++) for(int j=i;j<=P-3;j+=i) e[j].push_back(i); scanf("%d%d",&n,&K); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=n;i;i--) { if(a[i]) tot++;else continue; for(int j=0;j
=tot) ans=tot; else for(int i=tot;i>K;i--) ans=(ans+f[i]+(i==tot?K:0))%P; printf("%d\n",1ll*ans*fac%P);}

转载于:https://www.cnblogs.com/CK6100LGEV2/p/9408265.html

你可能感兴趣的文章
[51Nod1089] 最长回文子串 V2(Manacher算法)
查看>>
Asp.Net生命周期系列六
查看>>
php引用 =& 详解
查看>>
Codeforces 914D Bash and a Tough Math Puzzle (ZKW线段树)
查看>>
POJ 3009: Curling 2.0
查看>>
DLNA介绍(包含UPnP,2011/6/20 更新)
查看>>
ANGULARJS5从0开始(2) - 整合bootstrap和font-awesome
查看>>
Android 使用Parcelable序列化对象
查看>>
Python Web框架Django (零)
查看>>
Foxmail出现 错误信息:553 mailbox not found怎么解决
查看>>
spring_远程调用
查看>>
js 中基本数据类型和引用数据类型 ,,,, js中对象和函数的关系
查看>>
登录服务器,首先用到的5个命令
查看>>
多米诺骨牌
查看>>
区间DP 等腰三角形
查看>>
mysql 存储引擎对索引的支持
查看>>
Linq 学习(1) Group & Join--网摘
查看>>
asp.net 调用前台JS调用后台,后台掉前台JS
查看>>
【转】iOS 宏(define)与常量(const)的正确使用-- 不错
查看>>
【转】iOS开发UI篇—iPad和iPhone开发的比较
查看>>