[luogu3600]随机数生成器

令$P(k)$表示最小值的最大值小于等于$k$的概率,答案即为$\sum_{i=1}^{x}(P(i)-P(i-1))i=x-\sum_{i=1}^{x-1}P(i)$(其中利用到$P(x)=1$且$P(0)=0$)

$P(k)$的意义就是让每一个区间内都有一个小于等于$k$的数,考虑如何求出这个概率:

对于相互包含的区间,显然可以删掉较大的区间,再将剩下的区间排序后左右端点分别单调递增

假设剩下的区间依次为$[l_{1},r_{1}],[l_{2},r_{2}],...,[l_{q},r_{q}]$,令$f_{i}$表示仅考虑$r_{i}$以前,覆盖了前$i$个区间的概率,那么枚举最后一个位置$j$,令$j'=\max_{r_{k}<j}k$,则$f_{i}=\frac{x}{k}\sum_{j=l_{i}}^{r_{i}}(1-\frac{k}{x})^{r_{i}-j}f_{j'}$

首先将$(1-\frac{k}{x})^{r_{i}-j}$拆为$(1-\frac{k}{x})^{r_{i}}$和$(1-\frac{k}{x})^{-j}$,前者可以提到求和外面,后者仅与$j$有关,可以看作每一次求出$f_{i}$,就将$(r_{i},n]$用$f_{i}$区间覆盖,之后每一个点还有一个系数,要求区间求和,线段树即可维护

总复杂度为$o(mq\log_{2}n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2005
 4 #define mod 666623333
 5 #define L (k<<1)
 6 #define R (L+1)
 7 #define mid (l+r>>1)
 8 struct ji{
 9     int l,r;
10 }a[N];
11 int n,m,q,ans,st[N],vis[N],lst[N],f[N],tag[N<<2],val[N<<2],sum[N<<2];
12 bool cmp(ji x,ji y){
13     return (x.l<y.l)||(x.l==y.l)&&(x.r>y.r);
14 }
15 int ksm(int n,int m){
16     int s=n,ans=1;
17     while (m){
18         if (m&1)ans=1LL*ans*s%mod;
19         s=1LL*s*s%mod;
20         m>>=1;
21     }
22     return ans;
23 }
24 void upd(int k,int x){
25     tag[k]=x;
26     sum[k]=1LL*val[k]*x%mod;
27 }
28 void down(int k){
29     if (tag[k]){
30         upd(L,tag[k]);
31         upd(R,tag[k]);
32         tag[k]=0;
33     }
34 }
35 void build(int k,int l,int r,int x){
36     if (l==r){
37         val[k]=ksm(x,mod-1-l);
38         return;
39     }
40     build(L,l,mid,x);
41     build(R,mid+1,r,x);
42     val[k]=(val[L]+val[R])%mod;
43 }
44 void update(int k,int l,int r,int x,int y,int z){
45     if ((l>y)||(x>r))return;
46     if ((x<=l)&&(r<=y)){
47         upd(k,z);
48         return;
49     }
50     down(k);
51     update(L,l,mid,x,y,z);
52     update(R,mid+1,r,x,y,z);
53     sum[k]=(sum[L]+sum[R])%mod;
54 }
55 int query(int k,int l,int r,int x,int y){
56     if ((l>y)||(x>r))return 0;
57     if ((x<=l)&&(r<=y))return sum[k];
58     down(k);
59     return (query(L,l,mid,x,y)+query(R,mid+1,r,x,y))%mod;
60 }
61 int main(){
62     scanf("%d%d%d",&n,&m,&q);
63     for(int i=1;i<=q;i++)scanf("%d%d",&a[i].l,&a[i].r);
64     sort(a+1,a+q+1,cmp);
65     for(int i=1;i<=q;i++){
66         while ((st[0])&&(a[st[st[0]]].r>=a[i].r))vis[st[st[0]--]]=1;
67         st[++st[0]]=i;
68     }
69     int qq=0;
70     for(int i=1;i<=q;i++)
71         if (!vis[i])a[++qq]=a[i];
72     q=qq;
73     int inv_m=ksm(m,mod-2);
74     ans=m;
75     for(int i=1;i<m;i++){
76         build(1,1,n,1LL*(m-i)*inv_m%mod);
77         upd(1,1);
78         for(int j=1;j<=q;j++){
79             int s=1LL*i*inv_m%mod;
80             s=1LL*s*ksm(1LL*(m-i)*inv_m%mod,a[j].r)%mod;
81             f[j]=1LL*s*query(1,1,n,a[j].l,a[j].r)%mod;
82             if (a[j].r<n)update(1,1,n,a[j].r+1,n,f[j]);
83         }
84         ans=(ans+mod-f[q])%mod;
85     }
86     printf("%d",ans);
87 }
View Code

 

posted @ 2021-01-11 09:09  PYWBKTDA  阅读(107)  评论(0编辑  收藏  举报