zoukankan      html  css  js  c++  java
  • luogu P3600 随机数生成器【dp】

    把期望改成方案数最后除一下,设h[i]为最大值恰好是i的方案数,那么要求的就是Σh[i]*i
    首先包含其他区间的区间是没有意义的,用单调栈去掉
    然后恰好不好求,就改成h[i]表示最大值最大是i的方案数,求Σ(h[i]-h[i-1])*i即可
    然后考虑h怎么求,( h[i]=sum_{j=1}{n}ij*(m-1)^{n-j}*选j个点使得每个区间都有一个选中点 )
    设选j个点使得每个区间都有一个选中点为g[j],设f[i][j]为前i个必选i点一共选j个点的方案数,那么( g[j]=sum_{fr[i]==q}f[i][j] )
    然后考虑f怎么求,设fl[i]fr[i]分别是包含i的最左/右区间(如果没被包含就是左边第一个和右边第一个),( f[i][j]=sum_{fr[k]+1>=fl[i]} f[k][j-1] ),前缀和优化即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=2005,mod=666623333;
    int n,m,q,fl[N],fr[N],f[N][N],s[N][N],g[N],h[N],top,ans;
    struct qwe
    {
    	int l,r;
    }a[N],b[N];
    bool cmp(const qwe &a,const qwe &b)
    {
    	return a.l<b.l||(a.l==b.l&&a.r<b.r);
    }
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    int ksm(int a,int b)
    {
    	int r=1;
    	while(b)
    	{
    		if(b&1)
    			r=1ll*r*a%mod;
    		a=1ll*a*a%mod;
    		b>>=1;
    	}
    	return r;
    }
    int main()
    {
    	n=read(),m=read(),q=read();
    	for(int i=1;i<=q;i++)
    		a[i].l=read(),a[i].r=read();
    	sort(a+1,a+1+q,cmp);
    	for(int i=1;i<=q;i++)
    		if(i==1||a[i].l!=a[i-1].l)
    		{
    			while(top&&b[top].r>=a[i].r)
    				top--;
    			b[++top]=a[i];//cerr<<i<<endl;
    		}
    	q=top;
    	// for(int i=1;i<=q;i++)
    		// cerr<<b[i].l<<"   "<<b[i].r<<endl;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=q;j++)
    			if(b[j].r>=i)
    			{
    				fl[i]=j;
    				break;
    			}
    		for(int j=q;j>=1;j--)
    			if(b[j].l<=i)
    			{
    				fr[i]=j;
    				break;
    			}
    		if(!fl[i])
    			fl[i]=fr[i]+1;
    		// cerr<<fl[i]<<" "<<fr[i]<<endl;
    	}
    	f[0][0]=s[0][0]=1;
    	top=0;
    	for(int i=1;i<=n;i++)
    	{
    		s[i][0]=s[i-1][0];
    		for(int j=1;j<=i;j++)
    		{
    			while(top<i-1&&fr[top]+1<fl[i])
    				top++;
    			f[i][j]=(s[i-1][j-1]-(top?s[top-1][j-1]:0)+mod)%mod;
    			s[i][j]=(s[i-1][j]+f[i][j])%mod;
    		}
    	}
    	for(int j=1;j<=n;j++)
    		for(int i=1;i<=n;i++)
    			if(fr[i]==q)
    				g[j]=(g[j]+f[i][j])%mod;
    	for(int i=1;i<=m;i++)
    	{
    		for(int j=1;j<=n;j++)
    			h[i]=(h[i]+1ll*g[j]*ksm(i,j)%mod*ksm(m-i,n-j)%mod)%mod;
    		// cerr<<h[i]<<endl;
    		ans=(ans+1ll*(h[i]-h[i-1]+mod)*i%mod)%mod;
    	}
    	printf("%lld
    ",1ll*ans*ksm(ksm(m,n),mod-2)%mod);
    	return 0;
    }
    
  • 相关阅读:
    引物设计重复性查看
    NCBI获取指定区域基因序列及其引物设计
    视频录制软件——Bandicam使用介绍
    SX知识学习——IGV
    常用网站总结
    计算机知识学习——window上配置perl环境(转)
    ubuntu virtualenv安装
    Windows下使用virtualenv
    linux ssh连接设置
    linux 搭建FTP
  • 原文地址:https://www.cnblogs.com/lokiii/p/10832698.html
Copyright © 2011-2022 走看看