\(\color{#0066ff}{ 题目描述 }\)

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\) 取模之后的结果。

\(\color{#0066ff}{输入格式}\)

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

\(\color{#0066ff}{输出格式}\)

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

\(\color{#0066ff}{输入样例}\)

4 0
0 0 1 1

\(\color{#0066ff}{输出样例}\)

5 0
1 0 1 1 1

\(\color{#0066ff}{数据范围与提示}\)

对于 \(0\%\) 的测试点,和样例一模一样;

对于另外 \(30\%\) 的测试点,\(n \leq 10\);

对于另外 \(20\%\) 的测试点,\(n \leq 100\);

对于另外 \(30\%\) 的测试点,\(n \leq 1000\);

对于 \(100\%\) 的测试点,\(1 \leq n \leq 100000, 0 \leq k \leq n\);

对于以上每部分测试点,均有一半的数据满足 \(k = n\)。

\(\color{#0066ff}{题解}\)

这是一个很好?的期望DP

每次按下一个开关,只会影响它约数的灯的状态

预处理出每个开关能改变的灯, 用vector存

枚举因子是\(O(n\sqrt{n})\)的,因为会有一些浪费(非因子也被枚举了)

考虑枚举倍数,这样的复杂度是\(O(nlogn)\)的,就可以了

可以发现,按下当前的按钮,当前的灯的状态一定会改变,而它后面的灯的状态不变

也就是说,从后往前来,遇到亮的灯就按相应按钮,最多n次,就可以全部熄灭

而且,可以发现,按按钮的顺序不影响

所以我们设\(f[i]\) 代表按\(i\)次开关可以将灯全部熄灭的状态转移到按\(i - 1\)次开关将灯全部熄灭的状态的期望步数

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

n个开关, 有i个是正确的,n-i个是错误的,会增加一个步数,然后从\(i + 1\to i-1\) 需要\(f[i+1]+f[i]\)次操作

\(f[n]=1\)

如果总操作数都比k小,那么期望就是操作数了

否则累计从k到总操作数的f值,别忘了最后+k

还要乘n的阶乘,因为模数是质数还算有点良心,递推时直接乘逆元,最后再乘阶乘就行

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; int x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int mod = 1e5 + 3;
const int maxn = 1e5 + 10;
LL ksm(LL x, LL y) {
LL re = 1LL;
while(y) {
if(y & 1) re = re * x % mod;
x = x * x % mod;
y >>= 1;
}
return re;
}
int b[maxn];
LL f[maxn], ans;
using std::vector;
vector<int> g[maxn];
int n, k, num;
signed main() {
n = in(), k = in();
for(int i = 1; i <= n; i++) b[i] = in();
for(int i = 1; i <= n; i++)
for(int j = i; j <= n; j += i)
g[j].push_back(i);
for(int i = n; i >= 1; i--)
if(b[i]) {
num++;
for(int j = 0; j < (int)g[i].size(); j++) b[g[i][j]] ^= 1;
}
if(num <= k) ans = num;
else {
f[n] = 1;
for(LL i = n - 1; i >= 1; i--) f[i] = (1LL + ((n - i) * ksm(i, mod - 2) % mod) * (f[i + 1] + 1LL) % mod) % mod;
for(int i = num; i > k; i--) (ans += f[i]) %= mod;
(ans += k) %= mod;
}
for(int i = 1; i <= n; i++) (ans *= i) %= mod;
printf("%lld", ans);
return 0;
}

考试时看错题了。。。以为是到达小于等于k步的期望,一直不出样例qwq

P3750 [六省联考2017]分手是祝愿 期望DP的更多相关文章

  1. [BZOJ4872][六省联考2017]分手是祝愿(期望DP)

    4872: [Shoi2017]分手是祝愿 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 516  Solved: 342[Submit][Statu ...

  2. [六省联考2017]分手是祝愿 期望DP

    表示每次看见期望的题就很懵逼... 但是这题感觉还是值得一做,有可借鉴之处 要是下面这段文字格式不一样的话(虽然好像的确不一样,我也不知道为什么,是直接从代码里面复制出来的,因为我一般都是习惯在代码里 ...

  3. [六省联考2017]分手是祝愿——期望DP

    原题戳这里 首先可以确定的是最优策略一定是从大到小开始,遇到亮的就关掉,因此我们可以\(O(nlogn)\)的预处理出初始局面需要的最小操作次数\(tot\). 然后容(hen)易(nan)发现即使加 ...

  4. BZOJ 4872 luogu P3750 [六省联考2017]分手是祝愿

    4872: [Shoi2017]分手是祝愿 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description ...

  5. 洛谷P3750 [六省联考2017]分手是祝愿(期望dp)

    传送门 嗯……概率期望这东西太神了…… 先考虑一下最佳方案,肯定是从大到小亮的就灭(这个仔细想一想应该就能发现) 那么直接一遍枚举就能$O(nlogn)$把这个东西给搞出来 然后考虑期望dp,设$f[ ...

  6. luogu P3750 [六省联考2017]分手是祝愿

    luogu loj 可以发现在最优策略中,每种操作最多只会做一次,并且操作的先后顺序并不会影响答案,所以考虑从后往前扫,碰到一个\(1\)就对这个位置\(i\)进行操作,这样的操作一定是最优策略.记最 ...

  7. 洛谷 P3750 [六省联考2017]分手是祝愿

    传送门 题解 //Achen #include<algorithm> #include<iostream> #include<cstring> #include&l ...

  8. [bzoj4872] [洛谷P3750] [六省联考2017] 分手是祝愿

    Description Zeit und Raum trennen dich und mich. 时空将你我分开. \(B\) 君在玩一个游戏,这个游戏由 \(n\) 个灯和 \(n\) 个开关组成, ...

  9. 洛谷 P3750 - [六省联考2017]分手是祝愿(期望 dp)

    题面传送门 首先我们需注意到这样一个性质:那就是对于任何一种状态,将其变为全 \(0\) 所用的最小步数的方案是唯一的--考虑编号为 \(n\) 的灯,显然如果它原本是暗着的就不用管它了,如果它是亮着 ...

随机推荐

  1. Redis 复制技术和高可用sentinel(哨兵模式)

    redis的复制技术和高可用(哨兵模式) 1 复制 为什么要复制 实现数据的多副本存储,从而可以实现服务的高可用 提供更好的读性能复制技术的关键点及难点 如何指定被复制对象 增量还是全量以及如何实现增 ...

  2. spring特点与好处

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development a ...

  3. tomcat 三种部署方式以及server.xml文件的几个属性详解

    一.直接将web项目文件件拷贝到webapps目录中 这是最常用的方式,Tomcat的Webapps目录是Tomcat默认的应用目录,当服务器启动时,会加载所有这个目录下的应用.如果你想要修改这个默认 ...

  4. ABP仓储

    简介 我们都知道ABP已经实现了仓储模式,支持EF core 和dapper 进行数据库的连接和管理,可以很方便的注入仓储来操作你的数据,不需要自己单独定义一个仓储来实现,通用的仓储实现了通用的cru ...

  5. HBase入门基础教程 HBase之单机模式与伪分布式模式安装

    在本篇文章中,我们将介绍Hbase的单机模式安装与伪分布式的安装方式,以及通过浏览器查看Hbase的用户界面.搭建HBase伪分布式环境的前提是我们已经搭建好了Hadoop完全分布式环境,搭建Hado ...

  6. 为SSRS配置SMTP服务器身份验证

    此处设置外邮地址却无法填写邮箱密码 一.安装SMTP服务 1.在服务管理器中单击“功能” 2.单击“添加功能”打开“添加功能向导”对话框 3.在“选择功能”页上选择“SMTP服务器”并选择“添加必须的 ...

  7. PHP中几种加密形式

    1.Md5加密和Crypt都是单向加密: 登陆时把登录密码转为md5值,然后和数据库中的进行比较. 其中crypt中的盐值支持多种: 以CRYPT_STD_DES是以/0-9A-Za-z/中的两个字符 ...

  8. 全文检索技术---Lucene

    1       Lucene介绍 1.1   什么是Lucene Lucene是apache下的一个开源的全文检索引擎工具包.它为软件开发人员提供一个简单易用的工具包(类库),以方便的在目标系统中实现 ...

  9. ROS Learning-025 (提高篇-003 A Mobile Base-01) 控制移动平台

    ROS 提高篇 A Mobile Base-01 - 控制移动平台 - 基本知识 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 ...

  10. Blender 安装

    Blender 安装 Blender 安装 windows 上安装 Blender 搞定 Ubuntu Linux 上安装 Blender 搞定 windows 上安装 Blender Step 1 ...