前言
一道暴力就要用积分的题
整理一下思路
题目相关
题目大意
有
n
n
n个实数
x
1
,
x
2
⋅
⋅
⋅
x
n
x_1,x_2···x_n
x1,x2⋅⋅⋅xn,其中
x
i
x_i
xi在
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]中均匀随机
求
m
a
x
(
(
∑
x
i
)
m
,
0
)
max((\sum x_i)^m,0)
max((∑xi)m,0)的期望
数据范围
1 ≤ n ≤ 10 , 1 ≤ m ≤ 100 , − 1 0 6 ≤ l i ≤ r i ≤ 1 0 6 1\le n\le10,1\le m\le100,-10^6\le l_i\le r_i\le 10^6 1≤n≤10,1≤m≤100,−106≤li≤ri≤106
题解
暴力
有一档
n
=
1
n=1
n=1的部分分
我们发现这档部分分很好拿,当答案为正的时候直接积分即可
因为
∫
x
m
=
x
m
+
1
m
+
1
\int x^m=\frac{x^{m+1}}{m+1}
∫xm=m+1xm+1
那么
∫
l
i
r
i
x
m
=
r
i
m
+
1
−
l
i
m
+
1
m
+
1
\int_{l_i}^{r_i} x^m=\frac{r_i^{m+1}-l_i^{m+1}}{m+1}
∫lirixm=m+1rim+1−lim+1
正解
我们发现
n
n
n变得比较大的时候,每个位置概率可能会有所不同,所以本题并不好做
其中
a
,
b
a,b
a,b均为一个多项式
我们构造一种用来存概率的函数
f
(
x
)
=
{
a
(
x
>
R
)
b
(
x
≤
R
)
f(x)=\begin{cases}a&(x>R)\\b&(x\le R)\end{cases}
f(x)={ab(x>R)(x≤R)
我们发现,对于一组
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]的情况可以表示成两个函数相减即
{
0
(
x
>
r
i
)
1
r
i
−
l
i
(
x
≤
r
i
)
−
{
0
(
x
>
l
i
)
1
r
i
−
l
i
(
x
≤
l
i
)
\begin{cases}0&(x>r_i)\\ \frac{1}{r_i-l_i}&(x\le r_i)\end{cases}-\begin{cases}0&(x>l_i)\\\frac{1}{r_i-l_i}&(x\le l_i)\end{cases}
{0ri−li1(x>ri)(x≤ri)−{0ri−li1(x>li)(x≤li)
而对于多组
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]并在一起的情况,我们发现
f
∗
g
(
x
)
f*g(x)
f∗g(x)就是我们想要的运算
那么
∏
i
=
1
n
(
{
0
(
x
>
r
i
)
1
r
i
−
l
i
(
x
≤
r
i
)
−
{
0
(
x
>
l
i
)
1
r
i
−
l
i
(
x
≤
l
i
)
)
\prod_{i=1}^n\left(\begin{cases}0&(x>r_i)\\ \frac{1}{r_i-l_i}&(x\le r_i)\end{cases}-\begin{cases}0&(x>l_i)\\\frac{1}{r_i-l_i}&(x\le l_i)\end{cases}\right)
i=1∏n({0ri−li1(x>ri)(x≤ri)−{0ri−li1(x>li)(x≤li))
就是最终的概率分布函数了
我们来观察一下
f
∗
g
(
x
)
f*g(x)
f∗g(x)这个运算
由于我们发现,每个函数的
a
a
a都是0,那么我们现先讨论
a
=
0
a=0
a=0的情况
设 f ( x ) = { 0 ( x > R f ) b f ( x ≤ R f ) f(x)=\begin{cases}0&(x>R_f)\\b_f&(x\le R_f)\end{cases} f(x)={0bf(x>Rf)(x≤Rf), g ( x ) = { 0 ( x > R g ) b g ( x ≤ R g ) g(x)=\begin{cases}0&(x>R_g)\\b_g&(x\le R_g)\end{cases} g(x)={0bg(x>Rg)(x≤Rg)
为了方便,我们设
b
f
b_f
bf、
b
g
b_g
bg都是常值且值分别为
B
f
B_f
Bf、
B
g
B_g
Bg
讨论
f
∗
g
(
x
)
f*g(x)
f∗g(x)的值
对于
x
=
x
f
+
x
g
>
R
f
+
R
g
x=x_f+x_g>R_f+R_g
x=xf+xg>Rf+Rg的情况,
f
∗
g
(
x
)
=
0
f*g(x)=0
f∗g(x)=0
对于
x
=
x
f
+
x
g
≤
R
f
+
R
g
x=x_f+x_g\le R_f+R_g
x=xf+xg≤Rf+Rg的情况,
f
∗
g
(
x
)
=
(
R
f
+
R
g
−
x
)
B
f
∗
B
g
f*g(x)=(R_f+R_g-x)B_f*B_g
f∗g(x)=(Rf+Rg−x)Bf∗Bg
这样的话卷积仍然是原来形式的函数,并且
a
=
0
a=0
a=0,但结果的
b
b
b变成了一个多项式
我们进行推广,我们设
b
f
b_f
bf是常值
B
f
B_f
Bf、
b
g
b_g
bg是一个多项式
讨论
f
∗
g
(
x
)
f*g(x)
f∗g(x)的值
对于
x
=
x
f
+
x
g
>
R
f
+
R
g
x=x_f+x_g>R_f+R_g
x=xf+xg>Rf+Rg的情况,
f
∗
g
(
x
)
=
0
f*g(x)=0
f∗g(x)=0
对于
x
=
x
f
+
x
g
≤
R
f
+
R
g
x=x_f+x_g\le R_f+R_g
x=xf+xg≤Rf+Rg的情况,
f
∗
g
(
x
)
=
∫
x
−
R
f
R
g
b
f
(
x
+
x
−
y
)
b
g
(
y
)
d
y
=
∫
x
−
R
f
R
g
B
f
∗
b
g
(
y
)
d
y
=
B
f
∫
x
−
R
f
R
g
b
g
(
y
)
d
y
f*g(x)=\int_{x-R_f}^{R_g}b_f(x+x-y)b_g(y) dy=\int_{x-R_f}^{R_g}B_f*b_g(y) dy=B_f\int_{x-R_f}^{R_g}b_g(y) dy
f∗g(x)=∫x−RfRgbf(x+x−y)bg(y)dy=∫x−RfRgBf∗bg(y)dy=Bf∫x−RfRgbg(y)dy
这样的话卷积仍然是原来形式的函数,并且
a
=
0
a=0
a=0,但结果
b
b
b的多项式次数变高
1
1
1
定义完了卷积,我们发现我们无法定义减法,因为减法的结果将不能方便的用原来函数的形式表示出来
所以我们暴力把最终的概率分布函数的值暴力展开,展开成
O
(
2
n
)
\mathcal O(2^n)
O(2n)项
我们发现,把这
O
(
2
n
)
\mathcal O(2^n)
O(2n)项的值都算出来的复杂度是
O
(
2
n
∗
n
2
)
\mathcal O(2^n*n^2)
O(2n∗n2)的
得到了值分布的多项式后,我们可以将所有多项式按 R R R进行排序,然后根据区间进行积分即可
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
namespace fast_IO
{
const int IN_LEN=10000000,OUT_LEN=10000000;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
typedef long long ll;
#define rg register
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline T maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void Swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
char cu=getchar();x=0;bool fla=0;
while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
template <typename T> void printe(const T x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
const int maxn=2097152,mod=998244353;
inline int Md(const int x){return x>=mod?x-mod:x;}
template<typename T>
inline int pow(int x,T y)
{
rg int res=1;x%=mod;
for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;
return res;
}
namespace Poly///namespace of Poly
{
int W_[maxn],ha[maxn],hb[maxn],Inv[maxn];
inline void init(const int x)
{
rg int tim=0,lenth=1;
while(lenth<x)lenth<<=1,tim++;
for(rg int i=1;i<lenth;i<<=1)
{
const int WW=pow(3,(mod-1)/(i*2));
W_[i]=1;
for(rg int j=i+1,k=i<<1;j<k;j++)W_[j]=(ll)W_[j-1]*WW%mod;
}
Inv[0]=Inv[1]=1;
for(rg int i=2;i<x;i++)Inv[i]=(ll)(mod-mod/i)*Inv[mod%i]%mod;
}
int L;
inline void DFT(int*A)//prepare:init L
{
for(rg int i=0,j=0;i<L;i++)
{
if(i>j)Swap(A[i],A[j]);
for(rg int k=L>>1;(j^=k)<k;k>>=1);
}
for(rg int i=1;i<L;i<<=1)
for(rg int j=0,J=i<<1;j<L;j+=J)
for(rg int k=0;k<i;k++)
{
const int x=A[j+k],y=(ll)A[j+k+i]*W_[i+k]%mod;
A[j+k]=Md(x+y),A[j+k+i]=Md(mod+x-y);
}
}
void IDFT(int*A)
{
for(rg int i=1;i<L-i;i++)Swap(A[i],A[L-i]);
DFT(A);
}
inline int Quadratic_residue(const int a)
{
if(a==0)return 0;
int b=(rand()<<14^rand())%mod;
while(pow(b,(mod-1)>>1)!=mod-1)b=(rand()<<14^rand())%mod;
int s=mod-1,t=0,x,inv=pow(a,mod-2),f=1;
while(!(s&1))s>>=1,t++,f<<=1;
t--,x=pow(a,(s+1)>>1),f>>=1;
while(t)
{
f>>=1;
if(pow((int)((ll)inv*x%mod*x%mod),f)!=1)x=(ll)x*pow(b,s)%mod;
t--,s<<=1;
}
return min(x,mod-x);
}
struct poly
{
std::vector<int>A;
poly(){A.resize(0);}
poly(const int x){A.resize(1),A[0]=x;}
inline int&operator[](const int x){return A[x];}
inline int operator[](const int x)const{return A[x];}
inline void clear(){A.clear();}
inline unsigned int size()const{return A.size();}
inline void resize(const unsigned int x){A.resize(x);}
void RE(const int x)
{
A.resize(x);
for(rg int i=0;i<x;i++)A[i]=0;
}
void readin(const int MAX)
{
A.resize(MAX);
for(rg int i=0;i<MAX;i++)read(A[i]);
}
void putout()const
{
for(rg unsigned int i=0;i<A.size();i++)print(A[i]),putchar(' ');
}
inline poly operator +(const poly b)const
{
poly RES;
RES.resize(max(size(),b.size()));
for(rg unsigned int i=0;i<RES.size();i++)RES[i]=Md((i<size()?A[i]:0)+(i<b.size()?b[i]:0));
return RES;
}
inline poly operator -(const poly b)const
{
poly RES;
RES.resize(max(size(),b.size()));
for(rg unsigned int i=0;i<RES.size();i++)RES[i]=Md((i<size()?A[i]:0)+mod-(i<b.size()?b[i]:0));
return RES;
}
inline poly operator *(const int b)const
{
poly RES=*this;
for(rg unsigned int i=0;i<RES.size();i++)RES[i]=(ll)RES[i]*b%mod;
return RES;
}
inline poly operator /(const int b)const
{
poly RES=(*this)*pow(b,mod-2);
return RES;
}
inline poly operator *(const poly b)const
{
const int RES=A.size()+b.size()-1;
if(A.size()<=20||b.size()<=20)
{
poly c;c.RE(RES);
for(rg unsigned int i=0;i<size();i++)
for(rg unsigned int j=0;j<b.size();j++)
c[i+j]=((ll)A[i]*b[j]+c[i+j])%mod;
return c;
}
L=1;while(L<RES)L<<=1;
poly c;c.A.resize(RES);
memset(ha,0,L<<2);
memset(hb,0,L<<2);
for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];
for(rg unsigned int i=0;i<b.A.size();i++)hb[i]=b.A[i];
DFT(ha),DFT(hb);
for(rg int i=0;i<L;i++)ha[i]=(ll)ha[i]*hb[i]%mod;
IDFT(ha);
const int inv=pow(L,mod-2);
for(rg int i=0;i<RES;i++)c.A[i]=(ll)ha[i]*inv%mod;
return c;
}
inline poly inv()const
{
poly C;
if(A.size()==1){C=*this;C[0]=pow(C[0],mod-2);return C;}
C.resize((A.size()+1)>>1);
for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];
C=C.inv();
L=1;while(L<(int)size()*2-1)L<<=1;
for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];
for(rg unsigned int i=0;i<C.size();i++)hb[i]=C[i];
memset(ha+A.size(),0,(L-A.size())<<2);
memset(hb+C.size(),0,(L-C.size())<<2);
DFT(ha),DFT(hb);
for(rg int i=0;i<L;i++)ha[i]=(ll)(2-(ll)hb[i]*ha[i]%mod+mod)*hb[i]%mod;
IDFT(ha);
const int inv=pow(L,mod-2);
C.resize(size());
for(rg unsigned int i=0;i<size();i++)C[i]=(ll)ha[i]*inv%mod;
return C;
}
/* inline poly inv()const
{
poly C;
if(A.size()==1){C=*this;C[0]=pow(C[0],mod-2);return C;}
C.resize((A.size()+1)>>1);
for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];
C=C.inv();
poly D=(poly)2-*this*C;
D.resize(size());
D=D*C;
D.resize(size());
return D;
}*///大常数版本
inline void Reverse(const int n)
{
A.resize(n);
for(rg int i=0,j=n-1;i<j;i++,j--)Swap(A[i],A[j]);
}
inline poly operator /(const poly B)const
{
if(size()<B.size())return 0;
poly a=*this,b=B;a.Reverse(size()),b.Reverse(B.size());
b.resize(size()-B.size()+1);
b=b.inv();
b=b*a;
b.Reverse(size()-B.size()+1);
return b;
}
inline poly operator %(const poly B)const
{
poly C=(*this)-(*this)/B*B;C.resize(B.size()-1);
return C;
}
inline poly diff()const
{
poly C;C.resize(size()-1);
for(rg unsigned int i=1;i<size();i++)C[i-1]=(ll)A[i]*i%mod;
return C;
}
inline poly inte()const
{
poly C;C.resize(size()+1);
for(rg unsigned int i=0;i<size();i++)C[i+1]=(ll)A[i]*Inv[i+1]%mod;
C[0]=0;
return C;
}
inline poly ln()const
{
poly C=(diff()*inv()).inte();C.resize(size());
return C;
}
inline poly exp()const
{
poly C;
if(size()==1){C=*this;C[0]=1;return C;}
C.resize((size()+1)>>1);
for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];
C=C.exp();C.resize(size());
poly D=(poly)1-C.ln()+*this;
D=D*C;
D.resize(size());
return D;
}
inline poly sqrt()const
{
poly C;
if(size()==1)
{
C=*this;C[0]=Quadratic_residue(C[0]);
return C;
}
C.resize((size()+1)>>1);
for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];
C=C.sqrt();C.resize(size());
C=(C+*this*C.inv())*(int)499122177;
C.resize(size());
return C;
}
inline poly operator >>(const unsigned int x)const
{
poly C;if(size()<x){C.resize(0);return C;}
C.resize(size()-x);
for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i+x];
return C;
}
inline poly operator <<(const unsigned int x)const
{
poly C;C.RE(size()+x);
for(rg unsigned int i=0;i<size();i++)C[i+x]=A[i];
return C;
}
inline poly Pow(const unsigned int x)const
{
for(rg unsigned int i=0;i<size();i++)
if(A[i])
{
poly C=((((*this/A[i])>>i).ln()*x).exp()*pow(A[i],x))<<(min(i*x,size()));
C.resize(size());
return C;
}
return *this;
}
inline void cheng(const poly&B)
{
for(rg unsigned int i=0;i<size();i++)A[i]=(ll)A[i]*B[i]%mod;
}
inline void jia(const poly&B)
{
for(rg unsigned int i=0;i<size();i++)A[i]=Md(A[i]+B[i]);
}
inline void dft()
{
memset(ha,0,L<<2);
for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];
DFT(ha);
resize(L);
for(rg int i=0;i<L;i++)A[i]=ha[i];
}
inline void idft()
{
memset(ha,0,L<<2);
for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];
IDFT(ha);
const int inv=pow(L,mod-2);
for(rg int i=0;i<L;i++)A[i]=(ll)ha[i]*inv%mod;
while(size()&&!A[size()-1])A.pop_back();
}
ll dai(int x)const
{
x=Md(x%mod+mod);
ll res=0;
for(rg unsigned int i=0,j=1;i<size();i++,j=(ll)j*x%mod)res=((ll)A[i]*j+res)%mod;
return res;
}
};
void fz(const int root,const int l,const int r,std::vector<int>&v,std::vector<poly>&A)
{
if(l==r)
{
A[root].resize(2);
A[root][0]=(mod-v[l])%mod;
A[root][1]=1;
return;
}
const int mid=(l+r)>>1;
fz(root<<1,l,mid,v,A),fz(root<<1|1,mid+1,r,v,A);
A[root]=A[root<<1]*A[root<<1|1];
}
void calc(const int root,const int l,const int r,std::vector<int>&v,std::vector<poly>&A,std::vector<poly>&B)
{
if(l==r)
{
v[l]=B[root][0];
return;
}
const int mid=(l+r)>>1;
B[root<<1]=B[root]%A[root<<1];
B[root<<1|1]=B[root]%A[root<<1|1];
calc(root<<1,l,mid,v,A,B),calc(root<<1|1,mid+1,r,v,A,B);
}
void multi_point_evaluation(const poly a,std::vector<int>&v)
{
std::vector<poly>A,B;A.resize(maxn),B.resize(maxn);
fz(1,0,v.size()-1,v,A);
B[1]=a%A[1];
calc(1,0,v.size()-1,v,A,B);
}
void fz2(const int root,const int l,const int r,std::vector<int>&y,std::vector<poly>&A,std::vector<poly>&B)
{
if(l==r)
{
B[root].resize(1),B[root][0]=y[l];
return;
}
const int mid=(l+r)>>1;
fz2(root<<1,l,mid,y,A,B),fz2(root<<1|1,mid+1,r,y,A,B);
B[root]=B[root<<1]*A[root<<1|1]+B[root<<1|1]*A[root<<1];
}
poly interpolation(std::vector<int>&x,std::vector<int>&y)
{
std::vector<poly>A,B;A.resize(maxn),B.resize(maxn);
fz(1,0,x.size()-1,x,A);
multi_point_evaluation(A[1].diff(),x);
for(rg unsigned int i=0;i<x.size();i++)y[i]=(ll)y[i]*pow(x[i],mod-2)%mod;
fz2(1,0,x.size()-1,y,A,B);
return B[1];
}
}///namespace of Poly
int n,m,l,r,CC[13][13];
struct POLY
{
Poly::poly a;
int limit;
POLY(){a.clear();limit=0;}
POLY operator *(const POLY Y)const
{
POLY c;
c.limit=limit+Y.limit;
Poly::poly zc=a.inte();
c.a.RE(zc.size());
for(rg unsigned int i=0;i<zc.size();i++)
for(rg unsigned j=0;j<=i;j++)
c.a[j]=((ll)CC[i][j]*zc[i]%mod*pow(Md(mod-Y.limit),i-j)+c.a[j])%mod;
c.a=((Poly::poly)zc.dai(limit)-c.a)*Y.a;
return c;
}
bool operator <(const POLY b)const
{
return limit<b.limit;
}
}f[11],g[11],s[1090];
Poly::poly lj,zc;
ll ans;
int main()
{
Poly::init(maxn);///namespace of Poly
for(rg int i=0;i<=10;i++)
{
CC[i][0]=CC[i][i]=1;
for(rg int j=1;j<i;j++)CC[i][j]=Md(CC[i-1][j]+CC[i-1][j-1]);
}
read(n),read(m);
for(rg int i=0;i<n;i++)
{
int l,r;read(l),read(r);
f[i].limit=l,g[i].limit=r;
f[i].a=Md(mod-pow(r-l,mod-2)),g[i].a=pow(r-l,mod-2);
}
for(rg int i=0;i<(1<<n);i++)
{
if(i&1)s[i]=g[0];
else s[i]=f[0];
for(rg int j=1;j<n;j++)
if(i&(1<<j))s[i]=s[i]*g[j];
else s[i]=s[i]*f[j];
}
std::sort(s,s+(1<<n));
const int sx=(m&1)?0:-1000000000;int las=1000000000;
for(rg int i=(1<<n)-1;i>=0&&s[i].limit>sx;i--)
{
zc=(lj<<m).inte();
ans+=zc.dai(las)-zc.dai(s[i].limit);
las=s[i].limit;
lj=lj+s[i].a;
}
zc=(lj<<m).inte();
ans+=zc.dai(las)-zc.dai(sx);
ans=Md(ans%mod+mod);
print(ans);
return flush(),0;
}
总结
一道感觉挺裸的积分题
式子推错调了好久