zoukankan      html  css  js  c++  java
  • 4.2 省选模拟赛 流浪者 容斥dp

    avatar
    avatar

    求出期望 所有情况很好搞 C(n+m-2,n-1).

    也就是说求出所有情况的和乘以上面总方案的逆元即可。

    可以发现所有情况和经过多少个障碍点有关 和所处位置无关。

    简单的设f[i]表示从1,1到n,m经过i个障碍点的方案数。

    可以发现求出这个数组就得到了答案。

    发现每过一个障碍点 体力就会除以2 所以过掉log个障碍点 以后体力都是1.

    我们只需要求出log个取值即可。

    由于障碍点之间是单向关系 所以可以从左到右dp f[i][j]表示前i个点经过了j个障碍点的方案数。

    转移?f[k][j-1]?不能这样做 显然这样会有重复 我上午也思考了很久。

    考虑容斥 从1,1到当前点总方案已知 -不合法方案:到达当前点经过了多余j个障碍点的方案+少于j个的方案。

    观察后面的形式 我们已经推出j-1了 所以后面的已知。

    前者多余j个的方案 f[k][j+1]...f[k][j+w]?显然还是会重复。

    代表元容斥 考虑一条路径到达i这个点多余了j个点的这样的路径 必然存在到达i之间的某个点的状态为j 这样不管怎么走最后到i都是不合法的。

    所以有f[k][j]发现这些方案不可能交叉 这也叫做代表元容斥 最小状态表示总体。

    总复杂度K^2log 最后还要再多加一个点n,m来合并答案。(其实是求出一个障碍点都不经过的方案。

    数组不要开小了 别像我这个傻屌一样。

    const ll MAXN=200010;
    ll n,m,maxx,s,w,cc;
    ll f[MAXN][22],v[MAXN];//f[i][j]表示前i个点经过了j个点的方案数 第i个点必过.
    struct wy{ll x,y;}t[MAXN];
    ll fac[MAXN],inv[MAXN];
    inline ll ksm(ll b,ll p)
    {
    	ll cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=cnt*b%mod;
    		b=b*b%mod;p=p>>1;
    	}
    	return cnt;
    }
    inline ll C(ll a,ll b){if(b>a)return 0;return fac[a]*inv[b]%mod*inv[a-b]%mod;}
    inline void prepare()
    {
    	fac[0]=1;
    	rep(1,maxx,i)fac[i]=fac[i-1]*i%mod;
    	inv[maxx]=ksm(fac[maxx],mod-2);
    	fep(maxx-1,0,i)inv[i]=inv[i+1]*(i+1)%mod;
    }
    inline ll cmp(wy a,wy b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    inline ll V(ll x,ll y)
    {
    	ll w=t[y].x+t[y].y-t[x].x-t[x].y;
    	return C(w,t[y].x-t[x].x);
    }
    signed main()
    {
    	freopen("rover.in","r",stdin);
    	freopen("rover.out","w",stdout);
    	get(n);get(m);get(w);get(s);
    	maxx=n+m;prepare();
    	rep(1,w,i)
    	{
    		ll get(x);ll get(y);
    		t[i]=(wy){x,y};
    	}
    	ll ww=s;v[0]=s;
    	while(1)
    	{
    		ww=(ww>>1)+(ww&1);
    		if(ww==1)break;
    		v[++cc]=ww;
    	}
    	++w;++cc;
    	t[w]=(wy){n,m};
    	sort(t+1,t+w+1,cmp);
    	rep(1,w,i)
    	{
    		ll sum=0;
    		rep(1,cc,j)
    		{
    			f[i][j]=C(t[i].x+t[i].y-2,t[i].x-1)-sum;
    			rep(1,i-1,k)
    			{
    				if(t[k].x<=t[i].x&&t[k].y<=t[i].y)
    				f[i][j]=(f[i][j]-f[k][j]*V(k,i)%mod)%mod;
    			}
    			sum=(sum+f[i][j])%mod;
    		}
    	}
    	ll sum=C(n+m-2,n-1);
    	ll ans=0;
    	rep(1,cc,i)
    	{
    		sum=(sum-f[w][i])%mod;
    		ans=(ans+f[w][i]*v[i-1])%mod;
    	}
    	ans=((ans+sum)%mod+mod)%mod;
    	putl(ans*ksm(C(n+m-2,n-1),mod-2)%mod);
    	return 0;
    }
    
  • 相关阅读:
    ajax执行失败原因
    js中使用trim
    使用Nginx做WebSockets代理教程
    Nginx负载均衡服务器实现会话粘贴的几种方式
    如何利用Nginx的缓冲、缓存优化提升性能
    apache虚拟目录配置实例
    nginx提示地址或端口被占用解决
    安装成功的nginx如何添加未编译安装模块
    新增存储用Parted分区并建LVM卷
    服务器链接状态统计
  • 原文地址:https://www.cnblogs.com/chdy/p/12621385.html
Copyright © 2011-2022 走看看