题目大意

  有一个 \(n\times m\) 的矩阵 \(A\),每个元素都是 \([0,1]\) 内的等概率随机实数,记 \(s_i=\sum_{j=1}^mA_{i,j}\),求 \(\lfloor\min s_i\rfloor^k\) 的期望。

  对 \(998244353\) 取模。

  \(n\leq {10}^9,m\leq 5\times {10}^5,k\leq {10}^9\)

题解

  我们只用求 \(\lfloor s_i\rfloor\) 为 \(0\) 到 \(m-1\) 中每个值的概率就好了。

  记 \(b_i=\sum_{j=1}^iA_{1,j}-\lfloor\sum_{j=1}^iA_{1,j}\rfloor,c_i=\lfloor\sum_{j=1}^iA_{1,j}\rfloor\),那么 \(b_i\) 也在 \([0,1]\) 间等概率随机。我们可以直接忽略 \(b_i\) 相同的情况。这样就可以把 \(b\) 看成一个排列。

  可以发现,\(c_i>c_{i-1}\) 当且仅当 \(b_i<b_{i-1}\)。

  那么只用对于每个 \(i\) 计算有多少种 \(c_j>c_{j-1}\) 的个数为 \(i\) 的情况就好了。记这个东西为 \(A_{m,i}\)。

  怎么算呢?

  那么 \(\frac{1}{n!}\sum_{i=0}^mA_{n,i}\) 为 \(x_1+x_2+\ldots+x_n\leq m+1(0\leq x_i\leq 1)\) 的概率

  记 \(h_n(x)\) 为 \(x_1+x_2+\ldots+x_n\leq x(x_i\geq 0)\) 的概率。

  那么有

\[h_1(x)=x\\
h_i(x)=\int_0^xh_{i-1}(x-z)~dz=\int_0^xh_{i-1}(z)~dz=\frac{x^i}{i!}
\]

枚举有多少个 \(x_i>1\) 进行容斥,那么就有:

\[\begin{align}
\frac{1}{n!}\sum_{i=0}^mA_{n,i}&=\sum_{i=0}^{m+1}{(-1)}^i\binom{n}{i}h_n(m+1-i)\\
\frac{1}{n!}A_{n,m}&=\sum_{i=0}^{m+1}{(-1)}^i\binom{n}{i}h_n(m+1-i)-\sum_{i=0}^{m}{(-1)}^i\binom{n}{i}h_n(m-i)\\
&=\sum_{i=0}^{m+1}{(-1)}^i\binom{n}{i}h_n(m+1-i)+\sum_{i=0}^{m+1}{(-1)}^i\binom{n}{i-1}h_n(m+1-i)\\
&=\sum_{i=0}^{m+1}{(-1)}^i\binom{n+1}{i}h_n(m+1-i)\\
&=\frac{1}{n!}\sum_{i=0}^{m+1}{(-1)}^i\binom{n+1}{i}{(m+1-i)}^n\\
A_{n,m}&=\sum_{i=0}^{m+1}{(-1)}^i\binom{n+1}{i}{(m+1-i)}^n
\end{align}
\]

  这样就可以在 \(O(m\log m)\) 内计算出 \(A_{m,0}\ldots A_{m,m}\) 了。

  时间复杂度:\(O(m\log m)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<cmath>
#include<vector>
#include<assert.h>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void open2(const char *s){
#ifdef DEBUG
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=1200000;
const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
namespace ntt
{
const int W=1048576;
int rev[N];
ll w[N];
void init()
{
ll s=fp(3,(p-1)/W);
w[0]=1;
for(int i=1;i<W/2;i++)
w[i]=w[i-1]*s%p;
}
void ntt(ll *a,int n,int t)
{
for(int i=1;i<n;i++)
{
rev[i]=(rev[i>>1]>>1)|(i&1?n>>1:0);
if(rev[i]>i)
swap(a[i],a[rev[i]]);
}
for(int i=2;i<=n;i<<=1)
for(int j=0;j<n;j+=i)
for(int k=0;k<i/2;k++)
{
ll u=a[j+k];
ll v=a[j+k+i/2]*w[W/i*k];
a[j+k]=(u+v)%p;
a[j+k+i/2]=(u-v)%p;
}
if(t==-1)
{
reverse(a+1,a+n);
ll inv=fp(n,p-2);
for(int i=0;i<n;i++)
a[i]=a[i]*inv%p;
}
}
void mul(ll *a,ll *b,ll *c,int n,int m,int l)
{
static ll a1[N],a2[N];
int k=1;
while(k<=n+m)
k<<=1;
for(int i=0;i<k;i++)
a1[i]=a2[i]=0;
for(int i=0;i<=n;i++)
a1[i]=a[i];
for(int i=0;i<=m;i++)
a2[i]=b[i];
ntt::ntt(a1,k,1);
ntt::ntt(a2,k,1);
for(int i=0;i<k;i++)
a1[i]=a1[i]*a2[i]%p;
ntt::ntt(a1,k,-1);
for(int i=0;i<=l;i++)
c[i]=a1[i];
}
}
ll inv[N],fac[N],ifac[N];
int n,m,k;
ll f[N];
ll a[N],b[N],c[N];
ll binom(int x,int y)
{
return fac[x]*ifac[y]%p*ifac[x-y]%p;
}
int main()
{
open("b");
ntt::init();
inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(int i=2;i<=500010;i++)
{
inv[i]=-p/i*inv[p%i]%p;
fac[i]=fac[i-1]*i%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
scanf("%d%d%d",&n,&m,&k); for(int i=0;i<=m+1;i++)
{
a[i]=(i&1?-1:1)*ifac[i]%p*ifac[m+1-i]%p;
b[i]=fp(i,m);
}
ntt::mul(a,b,c,m+1,m+1,m+1);
for(int i=0;i<m;i++)
f[i]=c[i+1]*fac[m+1]%p; for(int i=0;i<m;i++)
f[i]=f[i]*ifac[m]%p;
for(int i=m-1;i>=0;i--)
f[i]=(f[i]+f[i+1])%p;
for(int i=0;i<m;i++)
f[i]=fp(f[i],n)%p;
for(int i=0;i<m;i++)
f[i]=(f[i]-f[i+1])%p;
ll ans=0;
for(int i=0;i<m;i++)
ans=(ans+fp(i,k)*f[i])%p;
ans=(ans%p+p)%p;
printf("%lld\n",ans);
return 0;
}

【集训队作业2018】矩阵玩小凹 NTT的更多相关文章

  1. [UOJ422][集训队作业2018]小Z的礼物——轮廓线DP+min-max容斥

    题目链接: [集训队作业2018]小Z的礼物 题目要求的就是最后一个喜欢的物品的期望得到时间. 根据$min-max$容斥可以知道$E(max(S))=\sum\limits_{T\subseteq ...

  2. 【UOJ#422】【集训队作业2018】小Z的礼物(min-max容斥,轮廓线dp)

    [UOJ#422][集训队作业2018]小Z的礼物(min-max容斥,轮廓线dp) 题面 UOJ 题解 毒瘤xzy,怎么能搬这种题当做WC模拟题QwQ 一开始开错题了,根本就不会做. 后来发现是每次 ...

  3. 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物

    T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...

  4. UOJ#422. 【集训队作业2018】小Z的礼物

    #422. [集训队作业2018]小Z的礼物 min-max容斥 转化为每个集合最早被染色的期望时间 如果有x个选择可以染色,那么期望时间就是((n-1)*m+(m-1)*n))/x 但是x会变,中途 ...

  5. UOJ #449. 【集训队作业2018】喂鸽子

    UOJ #449. [集训队作业2018]喂鸽子 小Z是养鸽子的人.一天,小Z给鸽子们喂玉米吃.一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米.一只鸽子饱了当且仅当它吃了的玉米粒数量\(≥ ...

  6. 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)

    [UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...

  7. [集训队作业2018]蜀道难——TopTree+贪心+树链剖分+链分治+树形DP

    题目链接: [集训队作业2018]蜀道难 题目大意:给出一棵$n$个节点的树,要求给每个点赋一个$1\sim n$之内的权值使所有点的权值是$1\sim n$的一个排列,定义一条边的权值为两端点权值差 ...

  8. UOJ#428. 【集训队作业2018】普通的计数题

    #428. [集训队作业2018]普通的计数题 模型转化好题 所以变成统计有标号合法的树的个数. 合法限制: 1.根标号比子树都大 2.如果儿子全是叶子,数量B中有 3.如果存在一个儿子不是叶子,数量 ...

  9. UOJ#418. 【集训队作业2018】三角形

    #418. [集训队作业2018]三角形 和三角形没有关系 只要知道儿子放置的顺序,就可以直接模拟了 记录历史最大值 用一个pair(a,b):之后加上a个,期间最大值为增加b个 合并? A1+A2= ...

随机推荐

  1. Redux进阶(Redux背后的Flux)

    简介 Flux是一种搭建WEB客户端的应用架构,更像是一种模式而不是一个框架. 特点 单向数据流 与MVC的比较 1.传统的MVC如下所示(是一个双向数据流模型) 用户触发事件 View通知Contr ...

  2. 使用C# 操作存储过程,执行sql语句通用类

    如何使用C# 操作存储过程,执行sql语句? 闲话不多说,直接上代码:     /// <summary>    /// Sql通用类    /// </summary>    ...

  3. JavaScript 是如何工作的:JavaScript 的共享传递和按值传递

    摘要: 原始数据类型和引用数据类型的副本作为参数传递给函数. 原文:JavaScript 是如何工作的:JavaScript 的共享传递和按值传递 作者:前端小智 Fundebug经授权转载,版权归原 ...

  4. Openlayer 3加载本地ArcGIS切片

    第一篇博客,简单的开个头吧.希望自己能坚持记录.一般什么情况什么人需要这样的需求呢,伐木的光头强大哥说我们在深山老林里,没网的啊,地图就手机本地duang的加载一下吧.那么Server啊就要丢掉丢掉. ...

  5. 三星5.0以上设备最完美激活XPOSED框架的经验

    对于喜欢钻研手机的小伙伴来说,常常会接触到Xposed框架以及种类繁多功能强大的模块,对于5.0以下的系统版本,只要手机能获得Root权限,安装和激活Xposed框架是异常简易的,但随着系统版本的不断 ...

  6. php微信h5支付超简单!!!

    本示例应用于tp3.2版本  不懂私聊我QQ:1195989301 请备注来意! 代码链接 请点击下载 密码: ekd4 不喜欢打字望谅解.....

  7. linux下的别名机制

    相当于用户自己创建一个属于自己的命令.在当前用户的家目录下有一个.bashrc文件,编辑该文件: eg:alias cls='clear' 如果命令要生效需要重新登录.用户输入cls就可以达到清屏的目 ...

  8. 【转】Android Hook框架Xposed详解

    1 Introduction 1.1  概述 Xposed 是 GitHUB 上 rovo89 大大设计的一个针对 Android 平台的动态劫持项目,通过替换 /system/bin/app_pro ...

  9. OneHotEncoder独热编码和 LabelEncoder标签编码

    学习sklearn和kagggle时遇到的问题,什么是独热编码?为什么要用独热编码?什么情况下可以用独热编码?以及和其他几种编码方式的区别. 首先了解机器学习中的特征类别:连续型特征和离散型特征 拿到 ...

  10. 解决mySQL数据库锁表问题。

    先用这条命令查询数据库阻塞的进程 SELECT * FROM information_schema.innodb_trx 找到后在根据下图这个字段:try_mysql_thread_id 作为这条数据 ...