LOJ - 6513 「雅禮集訓 2018 Day10」足球大戰
阿新 • • 發佈:2020-11-28
\(\text{Solution}\)
一看資料範圍就覺得一定是 \(\text{DP}\)。
顯然有 \(f[i][j][k]\) 表示在第 \(i\) 場,主隊贏了 \(j\) 局,客隊贏了 \(k\) 局。然後有個比較經典的優化:因為只要求 \(j>k\) 的狀態,設 \(f[i][j]\) 表示在第 \(i\) 場,主隊贏的局數比客隊多 \(j\) 局,狀態轉移方程(設 \(p1,p2\) 分別為主隊/客隊獲勝概率):
\[f[i][j]=f[i-1][j]\times [(p1\times p2)+(1-p1)\times(1-p2)]+f[i-1][j+1]\times (1-p1)\times p2+f[i-1][j-1]\times p1\times (1-p2) \]然後我就優化不動了,連矩陣加速這麼離譜的做法都想了一會,死磕了很久。
考試後發現老師的 \(n^2\) 做法和我的不一樣:直接暴力選 \(j,k\),和之前 \(n^3\) 的 \(\text{DP}\) 的 \(j,k\) 一樣,選了之後算出概率再乘一個組合數:
\[ans=\sum_{j=1}^{n} p1^{j}\times(1-p1)^{n-j}\times \text C(n,j)\times \sum_{k=0}^{j-1} p2^k \times (1-p2)^{n-k}\times \text{C}(n,k) \]看上去非常之暴力,但是你會發現後面的那個求和可以用一個 \(tmp\)
注意只能開一個 \(1e7\) 的陣列,發現組合數遞推其實只要逆元陣列就夠了。
然後有些情況需要特判。
\(\text{Summary}\)
有的時候一道題有很多個看上去很暴力的做法,但是很好優化,所以當優化不動的時候,
建議回爐重造。
\(\text{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,'\n'),0; if(p1==1) return print((1ll-qkpow(p2,n)+mod)%mod,'\n'),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,'\n'); return 0; }