zoukankan      html  css  js  c++  java
  • LOJ

    ( ext{Solution})

    一看数据范围就觉得一定是 ( ext{DP})

    显然有 (f[i][j][k]) 表示在第 (i) 场,主队赢了 (j) 局,客队赢了 (k) 局。然后有个比较经典的优化:因为只要求 (j>k) 的状态,设 (f[i][j]) 表示在第 (i) 场,主队赢的局数比客队多 (j) 局,状态转移方程(设 (p1,p2) 分别为主队/客队获胜概率):

    [f[i][j]=f[i-1][j] imes [(p1 imes p2)+(1-p1) imes(1-p2)]+f[i-1][j+1] imes (1-p1) imes p2+f[i-1][j-1] imes p1 imes (1-p2) ]

    然后我就优化不动了,连矩阵加速这么离谱的做法都想了一会,死磕了很久。

    考试后发现老师的 (n^2) 做法和我的不一样:直接暴力选 (j,k),和之前 (n^3)( ext{DP})(j,k) 一样,选了之后算出概率再乘一个组合数:

    [ans=sum_{j=1}^{n} p1^{j} imes(1-p1)^{n-j} imes ext C(n,j) imes sum_{k=0}^{j-1} p2^k imes (1-p2)^{n-k} imes ext{C}(n,k) ]

    看上去非常之暴力,但是你会发现后面的那个求和可以用一个 (tmp) 之类的存起来。

    注意只能开一个 (1e7) 的数组,发现组合数递推其实只要逆元数组就够了。

    然后有些情况需要特判。

    ( ext{Summary})

    有的时候一道题有很多个看上去很暴力的做法,但是很好优化,所以当优化不动的时候,

    建议回炉重造。

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    const int mod=1e9+7,maxn=1e7+5;
    
    int n,p1,p2,ip1,ip2,ans,tmp,pre1=1,pre2=1,InvIp1,InvIp2,tmp1,Temp,C,Inv[maxn],tmp2;
    
    inline int qkpow(int x,int y) {
    	int r=1;
    	while(y) {
    		if(y&1) r=1ll*r*x%mod;
    		x=1ll*x*x%mod; y>>=1;
    	}
    	return r;
    }
    
    inline int inv(int x) {
    	return qkpow(x,mod-2);
    }
    
    void init() {
    	Inv[1]=1;
    	rep(i,2,n) Inv[i]=1ll*(mod-mod/i)*Inv[mod%i]%mod;
    }
    
    int main() {
    	n=read(9); init();
    	p1=1ll*read(9)*inv(read(9))%mod; ip1=(1-p1+mod)%mod; InvIp1=inv(ip1);
    	p2=1ll*read(9)*inv(read(9))%mod; ip2=(1-p2+mod)%mod; InvIp2=inv(ip2);
    	if(p2==0) return print((1ll-qkpow((1ll-p1+mod)%mod,n)+mod)%mod,'
    '),0;
    	if(p1==1) return print((1ll-qkpow(p2,n)+mod)%mod,'
    '),0;
    	tmp1=qkpow(ip1,n-1); C=1; tmp2=qkpow(ip2,n);
    	rep(i,1,n) {
    		pre1=1ll*pre1*p1%mod;
    		tmp=(tmp+1ll*C*pre2%mod*tmp2%mod)%mod;
    		C=1ll*C*Inv[i]%mod*(n-i+1)%mod;
    		ans=(ans+1ll*C*pre1%mod*tmp1%mod*tmp%mod)%mod;
    		tmp1=1ll*tmp1*InvIp1%mod;
    		pre2=1ll*pre2*p2%mod;
    		tmp2=1ll*tmp2*InvIp2%mod;
    	}
    	print(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    计算机知识
    试题:论需求分析方法及应用
    试题:论信息系统开发方法及应用
    爬虫数据存储——安装docker和ElasticSearch(基于Centos7)
    go并发版爬虫
    go单任务版爬虫
    可变类型与不可变类型
    基本数据类型内置方法
    @submit.native.prevent作用
    获取当月第一天,今天的日期的方法
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14052743.html
Copyright © 2011-2022 走看看