[CSP-S模拟测试]:Seat(概率DP+数学)
题目描述
有$n+2$个座位等距地排成一排,从左到右编号为$0$至$n+1$。
最开始时$0$号以及$n+1$号座位上已经坐了一个小$G$,接下来会有$n$个小$G$依次找一个空座位坐下。由于小$G$们坐得太近就容易互相搏弈,每个小$G$会找一个当前离最近的小$G$距离最远的座位坐下。如果有多个备选的座位,这个小$G$会等概率选择其中一个。
给出$n$,求第$i$个坐下的小$G$坐在$j$号座位的概率,对$P$取模。具体来说,如果答案化为最简分数可以表示为$\frac{a}{b}$,你需要输出$a\times b^{−1}$,其中$b^{−1}=b^{P-2}(\mod P)$。
输入格式
从文件$seat.in$中读入数据。
一行两个整数$n,P$。
输出格式
输出到文件$seat.out$中。
输出$n$个整数,第$i$行第$j$个整数表示第$i$个小$G$坐在第$j$个座位的概率。
样例
样例输入:
4 10007
样例输出:
0 5004 5004 0
3336 1668 1668 3336
3336 1668 1668 3336
3336 1668 1668 3336
数据范围与提示
样例解释:
第一个小$G$会在中间两个位置中随机选择一个,接下来无论选哪个位置最近的距离都是$1$。
$\frac{1}{2}=5004(\mod 10^4+7),\frac{1}{3}=3336(\mod 10^4+7),\frac{1}{6}=1668(\mod 10^4+7)$。
数据范围:
对于所有数据,满足$2\leqslant n\leqslant 1024,2000\leqslant P\leqslant 30000$,$P$是质数。
本题共$25$个测试点,每个测试点$4$分。

题解
好玄学的一道玄学题……
一个结论是,对于任意一个人,他坐下时离最近的人的距离是固定的,不随前面的人的决策而改变。这样我们可以将所有人按坐下时的距离分成若干层。另一个结论是,无论之前每一层如何决策,轮到这一层时逬空区间的长度构成的可重集也是固定的。
对于最后一层特殊处理接下来均默认不是最后一层。对于之前的每一层,考虑在哪些空区间中央坐下可使得距离最大,其中可能会有一些长度为奇数的区间和一些长度为偶数的区间,而对于每个人来说,坐在任意一个奇数的区间的中央的概率都是相等的,偶数同理。
那么我们只需要知道,每个人有多大的概率坐在一个奇逯偶数区间的中央。考虑$DP$,$dp[i][j]$表示这一层已经坐下$i$个人之后,还有$j$个长度为偶数的区间的概率,转移只需考虑当前这个人坐了哪类区间即可。遤遰之后容易算出之前要求的概率。
区间长度为奇数时位置是固定的;考虑区间长度为偶数的情况,此时会出现两个位置可供选择,但无论选择哪一个,都会将区间划分成长度为$\frac{n}{2}$和$\frac{n}{2}−1$的两段。因此这两种选择具有对称性,我们只需要假定选择其中的一个,算出这种情况下之后的层的答案,即可对称地推出另一种情况下的答案。
瓶颈在利用对称性推答案的地方,主要看代码实现了,反正我是颓的代码。
时间复杂度:$\Theta(n^2\log n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int n,P,now;
int dp[1100][1100],ans[1100][1100],g[1100][1100],inv[1100],vis[1100],cnt[1100],odd[1100],pos[1100];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%P;
x=x*x%P;
y>>=1;
}
return res;
}
void pre_work()
{
for(int i=1;i<=n;i++)inv[i]=qpow(i,P-2);
vis[0]=vis[n+1]=1;now=n;
}
int main()
{
scanf("%d%d",&n,&P);
pre_work();
for(int i=1;i<=n;i++)
{
pair<int,int> lr=make_pair(0,0);
for(int j=0;j<=n;j++)
{
int flag=j+1;
while(!vis[flag])flag++;
if(flag-j>lr.second-lr.first){lr=make_pair(j,flag);}
j=flag-1;
}
cnt[lr.second-lr.first>>1]++;
if((lr.second-lr.first)&1)odd[lr.second-lr.first>>1]++;
pos[i]=lr.first+(lr.second-lr.first>>1);
vis[lr.first+(lr.second-lr.first>>1)]++;
}
for(int i=1;i<=n;i++)
{
if(!cnt[i])continue;
if(i==1)
{
for(int j=now-cnt[i]+1;j<=now;j++)
for(int k=now-cnt[i]+1;k<=now;k++)
ans[j][pos[k]]=inv[cnt[i]];
}
else
{
for(int j=0;j<=cnt[i];j++)
for(int k=0;k<=odd[i];k++)
dp[j][k]=0;
dp[0][odd[i]]=1;
for(int j=1;j<=cnt[i];j++)
{
int oddw=0,even=0;
for(int k=0;k<=odd[i];k++)
{
if(!dp[j-1][k])continue;
int frac=(cnt[i]-(j-1))+k;
int w=0;
if(k)
{
w=dp[j-1][k]*k*2%P*inv[frac]%P;
even=(even+w*inv[odd[i]<<1])%P;
dp[j][k-1]=(dp[j][k-1]+w)%P;
}
if(cnt[i]-odd[i])
{
w=dp[j-1][k]*(frac-2*k)%P*inv[frac]%P;
oddw=(oddw+w*inv[cnt[i]-odd[i]])%P;
dp[j][k]=(dp[j][k]+w)%P;
}
}
for(int k=now-cnt[i]+1;k<=now-cnt[i]+odd[i];k++)
{
ans[now-cnt[i]+j][pos[k]]=(ans[now-cnt[i]+j][pos[k]]+even)%P;
ans[now-cnt[i]+j][pos[k]+1]=(ans[now-cnt[i]+j][pos[k]+1]+even)%P;
}
for(int k=now-cnt[i]+odd[i]+1;k<=now;k++)
ans[now-cnt[i]+j][pos[k]]=(ans[now-cnt[i]+j][pos[k]]+oddw)%P;
}
for(int j=now-cnt[i]+1;j<=now-cnt[i]+odd[i];j++)
{
int L=pos[j]-i+1;
int R=pos[j]+i;
for(int k=L;k<=R;k++)
{
if(k==pos[j])continue;
for(int l=now+1;l<=n;l++)
{
g[l][k]=(g[l][k]+ans[l][k]*inv[2])%P;
g[l][k<pos[j]?k+i+1:k-i]=(g[l][k<pos[j]?k+i+1:k-i]+ans[l][k]*inv[2])%P;
}
}
for(int k=L;k<=R;k++)
for(int l=now+1;l<=n;l++)
{
ans[l][k]=g[l][k];
g[l][k]=0;
}
}
}
now-=cnt[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",ans[i][j]);
puts("");
}
return 0;
}
rp++
[CSP-S模拟测试]:Seat(概率DP+数学)的更多相关文章
- [CSP-S模拟测试]:题(DP+数学)
题目描述 出个题就好了.这就是出题人没有写题目背景的原因.你在平面直角坐标系上.你一开始位于$(0,0)$.每次可以在上/下/左/右四个方向中选一个走一步.即:从$(x,y)$走到$(x,y+1),( ...
- [CSP-S模拟测试]:B(DP+数学)
题目传送门(内部题45) 输入格式 第一行$3$个整数$n,m,P$.第二行$m$个整数,表示$m$次询问. 输出格式 一行$m$个整数表示答案. 样例 样例输入1: 2 4 40 1 2 3 样例输 ...
- HDU 4599 Dice (概率DP+数学+快速幂)
题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n). 析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦. 先分析F(n ...
- [CSP-S模拟测试]:大佬(kat)(数学期望)
题目描述 辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了.他发现$katarina$大佬真是太强了,于是就学习了一下$katarina$大佬的做题方法.比如这是一本有$n$道题的练习册,$ ...
- CF 148D D. Bag of mice (概率DP||数学期望)
The dragon and the princess are arguing about what to do on the New Year's Eve. The dragon suggests ...
- bzoj1415 [Noi2005]聪聪和可可【概率dp 数学期望】
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1415 noip2016 D1T3,多么痛的领悟...看来要恶补一下与期望相关的东西了. 这是 ...
- [CSP-S模拟测试]:题(DP)
题目描述 由于出题人赶时间所以没办法编故事来作为背景.一开始有$n$个苹果,$m$个人依次来吃苹果,第$i$个人会尝试吃$u_i$或$v_i$号苹果,具体来说分三种情况.$\bullet 1.$两个苹 ...
- [CSP-S模拟测试]:tree(DP)
题目传送门(内部题57) 输入格式 第一行包含一个数:$n$表示树的节点数.接下来$n-1$行,每行包含两个数:$u,v$表示无根树的一条边. 输出格式 输出$n$行,第$i$行包含一个浮点数,保留三 ...
- 2018.10.17 NOIP模拟 发电机(概率dp)
传送门 考试空间开大了爆零不然只有30分爆栈? 话说这题真的坑1e7没法写dfsdfsdfs 其实很好推式子. 考虑每个点安一个发动机的概率,推一波式子做个等比数列求和什么的可以证明出来是严格的1si ...
随机推荐
- hbase的TTL机制清除opentsdb的超时数据
我们发现用opentsdb向hbase写数据之后,磁盘占用率飙升得很快,我们存的业务数据只用保存一个月的即可,了解hbase的TTL机制可以清除相关表.相关行的超时数据,之前在数据备份时,我介绍了,o ...
- redis 设置密码 和 redis.config文件
- Windows + Ubuntu 16.04 双系统安装详细教程(转)
转载自:http://www.cnblogs.com/Duane/p/6776302.html 前言:本篇文章是对之前文章的更新,更新的主内容是把原来用手机拍摄的图片换成了虚拟机的截图,以及对磁盘划分 ...
- hdu-4292.food(类dining网络流建图)
Food Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- linux安装mysql(tar.gz)
1. 查看卸载自带的mysql # rpm -qa|grep MySQLMySQL-X.X.X#rpm -e MySQL-X.X.X # rpm -qa|grep mariadb #有些版本还得查看卸 ...
- [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...
- Redis主从同步、哨兵、集群
什么是主从同步(复制) 主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器.前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点 ...
- Python 中的作用域?
Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定. 当 Python 遇到一个变量的话,它会按照这的顺序进行搜索:本地作用域(Local)--->当前作用域被嵌入的本地作用域( ...
- vue.js(15)--vue的生命周期
生命周期钩子 生命周期钩子=生命周期函数=生命周期事件 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等 ...
- Java编码技巧与代码优化
本文参考整理自https://mp.weixin.qq.com/s/-u6ytFRp-ZAqdLBsMmuDMw 对于在本文中有所疑问的点可以去该文章查看详情 常量&变量 直接赋值常量值, 禁 ...