zoukankan      html  css  js  c++  java
  • Luogu P3600 随机数生成器

    Luogu P3600 随机数生成器

    题目描述

    sol研发了一个神奇的随机数系统,可以自动按照环境噪音生成真·随机数。

    现在sol打算生成(n)([1,x])的整数(a_1...a_n),然后进行一些询问。

    (q)次询问,每次询问i有两个参数(li)(ri),sol会计算(min_{li leq j leq ri} a_j)(a数组中下标在(li、ri)之间的数的最小值)。

    最后测试结果会是这些询问得到的结果的最大值。

    sol进行了很多次实验,现在他想问问你测试结果的期望大小是多少,对(666623333)取模。

    输入输出格式

    输入格式:

    第一行三个数(n、x、q)

    下面q行,第i行两个数表示(li)(ri)

    输出格式:

    一行一个数,表示答案。

    输入输出样例

    输入样例#1:

    2 2 1
    1 2
    

    输出样例#1:

    499967501
    

    输入样例#2:

    6 6 6
    1 3
    2 4
    3 5
    4 6
    5 6
    3 4
    

    输出样例#2:

    88571635
    

    根据整数期望公式:

    [egin{align} ans&=sum_{i=1}^xi*p(X=i)\ &=sum_{i=1}^xp(Xgeq i)\ &=sum_{i=1}^x1-p(X<i) end{align} ]

    因为是所有的最小值取最大值,所以(p(X<i))(p(Xgeq i))好求一些。

    我们考虑对每个(i)分别求。

    合法情况要求询问的每个区间中至少有一个(<i)的数。如果两个区间有包含关系,很明显大的区间没有用。将剩余的区间按左端点排序后,对于坐标上的每个点,包含它的区间的编号一定是连续的。所以我们将问题转换:有很多区间,选择一个区间的概率为(P),要选择一些区间将整个坐标轴覆盖,问概率。

    很明显这些区间的左右端点都是单调不下降的(去掉无用区间)。设(f_i)表示最后一个选择的区间为(i),并且将(r_i)以及之前的坐标都覆盖了的概率。

    [f_i=sum_{r_jgeq l_i-1}f_j*P*(1-P)^{i-j-1} ]

    前缀和优化一下单次(DP)就可以做到(O(n))了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 2005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=666623333;
    ll ksm(ll t,ll x) {
    	ll ans=1;
    	for(;x;x>>=1,t=t*t%mod)
    		if(x&1) ans=ans*t%mod;
    	return ans;
    }
    
    int n,x,m;
    struct interval {
    	int l,r;
    	bool operator <(const interval &a)const {
    		if(l!=a.l) return l<a.l;
    		return r>a.r;
    	}
    }s[N];
    
    interval st[N];
    int top;
    
    int L[N],R[N];
    ll ans;
    ll DP(ll p) {
    	if(p==1) return 1;
    	static ll f[N],pw[N],inv[N];
    	memset(f,0,sizeof(f));
    	
    	pw[0]=inv[0]=1;
    	for(int i=1;i<=n;i++) pw[i]=pw[i-1]*(mod+1-p)%mod;
    	inv[1]=ksm(mod+1-p,mod-2);
    	for(int i=2;i<=n;i++) inv[i]=inv[i-1]*inv[1]%mod;
    	f[0]=1;
    	int lx=0,rx=0;
    	ll sum=1;
    	for(int i=1;i<=n;i++) {
    		while(lx<=i&&R[lx]<L[i]-1) {
    			sum=(sum-f[lx]*inv[lx]%mod+mod)%mod;
    			lx++;
    		}
    		while(rx+1<i&&R[rx+1]>=L[i]-1) {
    			sum=(sum+f[rx+1]*inv[rx+1])%mod;
    			rx++;
    		}
    		f[i]=sum*p%mod*pw[i-1]%mod;
    	}
    	ll ans=0;
    	for(int i=1;i<=n;i++) {
    		if(R[i]==m) (ans+=f[i]*pw[n-i])%=mod;
    	}
    	return ans;
    }
    
    int main() {
    	n=Get(),x=Get(),m=Get();
    	for(int i=1;i<=m;i++) s[i].l=Get(),s[i].r=Get();
    	sort(s+1,s+1+m);
    	for(int i=1;i<=m;i++) {
    		while(top>=1&&st[top].r>=s[i].r) top--;
    		st[++top]=s[i];
    	}
    	
    	m=top;
    	for(int i=1;i<=m;i++) s[i]=st[i];
    	
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) if(s[j].l<=i&&i<=s[j].r) R[i]=j;
    		for(int j=m;j>=1;j--) if(s[j].l<=i&&i<=s[j].r) L[i]=j;
    	}
    	top=0;
    	for(int i=1;i<=n;i++) {
    		if(L[i]&&R[i]) L[++top]=L[i],R[top]=R[i];
    	}
    	n=top;
    	ll invx=ksm(x,mod-2);
    	for(int i=1;i<=x;i++) {
    		(ans+=mod+1-DP((i-1)*invx%mod))%=mod;
    	}
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    类 7.2访问控制与封装 笔记
    第七章 类(class)7.1 笔记
    10.4.3反向迭代器Reverse_iterator笔记
    10.4再探迭代器笔记
    10.3.4参数绑定 bind
    10.3lambda表达式笔记
    第10章 10.1-10.3笔记
    关于按下ctrl+z后,之后的cin失效的问题
    构造和改变一个string的其他方法
    BZOJ2527 & 洛谷3527:[Poi2011]Meteors——题解
  • 原文地址:https://www.cnblogs.com/hchhch233/p/11085314.html
Copyright © 2011-2022 走看看