题目:https://loj.ac/problem/2541

看了题解才会……有三点很巧妙。

1.分母如果变动,就很不好。所以考虑把操作改成 “已经选过的人仍然按 \( w_i \) 的概率被选,但是再次选中一个已经选过的人算作没有操作” 。

2.然后要容斥,考虑强制点集 S 的人在 1 号点之后被选、其余随意,那么

  \( ans=\sum\limits_{S} (-1)^{|S|} \sum\limits_{i=0}^{\infty} (1-\frac{w_1 + w_S}{A})^i \frac{w_1}{A} \)

  (其中 A 表示 \( \sum\limits_{i=1}^{n} w_i \) ,\( w_S \) 表示 \( \sum\limits_{i \in S} w_i \) )

  等比数列求和一下,就是 \( ans=\sum\limits_{S} (-1)^{|S|} \frac{w_1}{w_1+w_S} \)

3.注意到 \( \sum w <=1e5 \) ,所以考虑把那个式子里的分母看做多项式的次数!

  那么算一个 \( \prod\limits_{i=2}^{n} (1-x^{w_i}) \)(这是考虑选出一个点集 S 的过程)

  然后就是取 \( x^i \) 的系数 \( a_i \) ,给答案贡献 \( \frac{a_i}{w_1+i} \) ,最后答案再乘一个 \( w_1 \) 。

算那个连乘的式子,可以普通地分治。但注意到含有 k 个 w 的乘积式子的次数不是 k ,所以复杂度不是 \( T(n)=T(n/2)+O(nlogn) \) 。(可能是 n2logn?)

反正把 w 排个序再做就能了。不知道不排序是否也可以。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define vi vector<int>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=1e5+,M=(<<)+,mod=;
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;} int n,w[N],len,r[M],wn[M],wn2[M],inv[M];
void ntt_pre(int n)
{
for(len=;len<=n;len<<=);
for(int R=;R<=len;R<<=)
{
wn[R]=pw(,(mod-)/R);
wn2[R]=pw(,(mod-)-(mod-)/R);
inv[R]=pw(R,mod-);
}
}
void ntt(vi &a,bool fx)
{
for(int i=;i<len;i++)
if(i<r[i])swap(a[i],a[r[i]]);
for(int R=;R<=len;R<<=)
{
int Wn=fx?wn2[R]:wn[R];
for(int i=,m=R>>;i<len;i+=R)
for(int j=,w=;j<m;j++,w=(ll)w*Wn%mod)
{
int x=a[i+j],y=(ll)w*a[i+m+j]%mod;
a[i+j]=upt(x+y); a[i+m+j]=upt(x-y);
}
}
if(!fx)return; int iv=inv[len];
for(int i=;i<len;i++)a[i]=(ll)a[i]*iv%mod;
}
vi solve(int L,int R)
{
if(L==R)
{
vi ret; ret.resize(w[L]+);
ret[]=; ret[w[L]]=-;
return ret;
}
int mid=L+R>>;
vi a=solve(L,mid), b=solve(mid+,R);
int lm=a.size()-+b.size()-;
for(len=;len<=lm;len<<=);
for(int i=,j=len>>;i<len;i++)
r[i]=(r[i>>]>>)+((i&)?j:);
a.resize(len); b.resize(len);
ntt(a,); ntt(b,);
for(int i=;i<len;i++)a[i]=(ll)a[i]*b[i]%mod;
ntt(a,);
a.resize(lm+);
return a;
}
int main()
{
n=rdn(); int sm=;
for(int i=;i<=n;i++)
{ w[i]=rdn(); if(i>)sm+=w[i];}//if!!!
ntt_pre(sm);
sort(w+,w+n+);//
vi f=solve(,n); int ans=;
for(int i=;i<=sm;i++)
if(f[i])ans=(ans+(ll)f[i]*pw(upt(w[]+i),mod-))%mod;
ans=(ll)ans*w[]%mod;
printf("%d\n",ans);
return ;
}

LOJ 2541 「PKUWC2018」猎人杀——思路+概率+容斥+分治的更多相关文章

  1. LOJ #2541「PKUWC2018」猎人杀

    这样$ PKUWC$就只差一道斗地主了 假装补题补完了吧..... 这题还是挺巧妙的啊...... LOJ # 2541 题意 每个人有一个嘲讽值$a_i$,每次杀死一个人,杀死某人的概率为$ \fr ...

  2. loj#2541. 「PKUWC2018」猎人杀

    传送门 思路太清奇了-- 考虑容斥,即枚举至少有哪几个是在\(1\)号之后被杀的.设\(A=\sum_{i=1}^nw_i\),\(S\)为那几个在\(1\)号之后被杀的人的\(w\)之和.关于杀了人 ...

  3. 【LOJ】#2541. 「PKUWC2018」猎人杀

    题解 一道神仙的题>< 我们毙掉一个人后总的w的和会减少,怎么看怎么像指数算法 然而,我们可以容斥-- 设\(\sum_{i = 1}^{n} w_{i} = Sum\) 我们把问题转化一 ...

  4. loj#2542. 「PKUWC2018」随机游走(MinMax容斥 期望dp)

    题意 题目链接 Sol 考虑直接对询问的集合做MinMax容斥 设\(f[i][sta]\)表示从\(i\)到集合\(sta\)中任意一点的最小期望步数 按照树上高斯消元的套路,我们可以把转移写成\( ...

  5. 「PKUWC2018」猎人杀

    「PKUWC2018」猎人杀 解题思路 首先有一个很妙的结论是问题可以转化为已经死掉的猎人继续算在概率里面,每一轮一直开枪直到射死一个之前没死的猎人为止. 证明,设所有猎人的概率之和为 \(W\) , ...

  6. [LOJ2541]「PKUWC2018」猎人杀

    loj description 有\(n\)个猎人,每个猎人有一个仇恨度\(w_i\),每个猎人死后会开一枪打死一个还活着的猎人,打中每个猎人的概率与他的仇恨度成正比. 现在你开了第一枪,打死每个猎人 ...

  7. loj2541 「PKUWC2018」猎人杀 【容斥 + 分治NTT】

    题目链接 loj2541 题解 思路很妙啊, 人傻想不到啊 觉得十分难求,考虑容斥 由于\(1\)号可能不是最后一个被杀的,我们容斥一下\(1\)号之后至少有几个没被杀 我们令\(A = \sum\l ...

  8. LOJ2541. 「PKUWC2018」猎人杀 [概率,分治NTT]

    传送门 思路 好一个神仙题qwq 首先,发现由于一个人死之后分母会变,非常麻烦,考虑用某种方法定住分母. 我们稍微改一改游戏规则:一个人被打死时只打个标记,并不移走,也就是说可以被打多次但只算一次.容 ...

  9. loj2542 「PKUWC2018」随机游走 MinMax 容斥+树上高斯消元+状压 DP

    题目传送门 https://loj.ac/problem/2542 题解 肯定一眼 MinMax 容斥吧. 然后问题就转化为,给定一个集合 \(S\),问期望情况下多少步可以走到 \(S\) 中的点. ...

随机推荐

  1. js中的window对象:打开窗口

    ~~ window.open():打开一个窗口 里面需要放三个参数: 1.打开窗口(网页)的位置: 2.打开的方式(自身页面,新开页面): 其中_blank新开一个窗口 3.打开网页的属性: wind ...

  2. 测开之路七十七:性能测试蓝图之js

    //定义全局的editor = nullvar editor = null; //ace_editor的初始化函数function ace_editor() { var editor = ace.ed ...

  3. 思维导图初体验——openstack

    RABBITMQ memcache keystone glance nova neutron horizon cinder ceph

  4. iview 表格 某一列中设置radio

    在iview 表格 某一列中设置radio,说白了还是要在render中添加,方法为: { title: '业务参数设置', // key: 'pyCode', align: 'center', re ...

  5. pandas向左移动非空单元格

    碰到个小问题, 因为需要更改excel 的行为. 处理最多的还是excel的事, 不过看起来是excel.实际上对pandas 的库的熟悉.读取,更改,应用等等,方法. 十分有用. 先说需求,本来的表 ...

  6. c#继承与构造函数的调用

    1.实例化父类时,可以通过new子类来实例化父类,执行构造函数的顺序为:先执行父类的构造函数,再执行子类的构造函数. 2.实例化子类时,只可以new子类,执行顺序同上. 3.父类实例化后,只能执行父类 ...

  7. Linux 系统故障修复和修复技巧

    我发现Linux系统在启动过程中会出现一些故障,导致系统无法正常启动,我在这里写了几个应用单用户模式.GRUB命令操作.Linux救援模式的故障修复案例帮助大家了解此类问题的解决. 一.单用户模式 L ...

  8. Python笔记(十二)_文件

    文件的打开模式 'r':以只读的方式打开文件(默认) 'w':以写入的方式打开文件,会覆盖已存在的文件 'x':用写入的方式打开文件,如果文件已存在,会抛出异常 'a':用写入的方式打开文件,如果文件 ...

  9. 20190815 On Java8 第五章 控制流

    第五章 控制流 迭代语句 逗号操作符 在 Java 中逗号运算符(这里并非指我们平常用于分隔定义和方法参数的逗号分隔符)仅有一种用法:在 for 循环的初始化和步进控制中定义多个变量.我们可以使用逗号 ...

  10. vue手写轮播

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...