[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 }