题解 游戏

传送门

很好的题,我连暴力都不会打

建议复看题解
subtask1(n=1):每一轮都是独立的,A的胜率应该相等,于是列出等式 \(f = p + (1 - p)(1 - q)f\)

subtask2(p=q=0.5):此时胜率与剩余石子个数有关
所以令设 \(a_n\) 表示剩余n个石子A先手时A获胜的概率,\(b_n\) 表示剩余n个石子B先手时A获胜的概率
这个状态设计很好,既方便了二者互相转移也方便了下面矩阵优化
\(a_0 = 0, b_0 = 1\),试图递推
于是尝试用n的情况表示n+1的情况

\[a_{n+1}=\frac{1}{2}b_n+\frac{1}{2}b_{n+1} \]

\[b_{n+1}=\frac{1}{2}a_n+\frac{1}{2}a_{n+1} \]

将2式整体代入可得递推式

然后正解:
现在每个人有概率得到自己想要的一面
若A先手,A认为现在想投某一面更优,那么在当前这个石子被某一个人拿走之前她会一直想投这一面,B先手时对于B也是如此
若A先手,为了阻止A投到某一面,B也要选择投这一面,也就是说对于任意一个石子,A和B的决策相同
(开始复制)
那两个人的决策会是什么呢?n+1的情况与n的胜率有关
也即两者都希望少了一颗石子后会进入一个胜率更高的局面
于是根据 \(a_n, b_n\) 的大小分别转移即可
然后优化:对两种转移的 \(a_n+1,b_n+1\) 作差,发现每取一次二者的大小关系会交换
所以第一种转移被恰好执行 n / 2 次,第二种转移被恰好执行 (n + 1) / 2 次
矩乘优化即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
ll p, q;
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1ll; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
inline ll inv(ll a) {return qpow((a%mod+mod)%mod, mod-2);}
struct matrix{
	ll a[3][3];
	int n, m;
	matrix(){}
	matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
	void resize(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
	void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<(a[i][j]%mod+mod)%mod<<' '; cout<<endl;}}
	inline ll* operator [] (int t) {return a[t];}
	inline matrix operator * (matrix b) {
		matrix ans(n, b.m);
		for (int i=1; i<=n; ++i)
			for (int k=1; k<=m; ++k)
				for (int j=1; j<=b.m; ++j)
					ans[i][j]=(ans[i][j]+a[i][k]*b[k][j]%mod)%mod;
		return ans;
	}
}mat, t1, t2;
inline matrix qpow(matrix a, ll b) {matrix ans=a; --b; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}

signed main()
{
	freopen("game.in", "r", stdin);
	freopen("game.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read(); p=read()%mod; q=read()%mod;
		p=p*inv(1e8)%mod; q=q*inv(1e8)%mod;
		mat.resize(1, 2); t1.resize(2, 2); t2.resize(2, 2);
		mat[1][1]=0; mat[1][2]=1;
		t1[1][1]=p*(1-q)%mod*inv(1-p*q%mod)%mod; t1[2][1]=(1-p)*inv(1-p*q%mod)%mod;
		t1[1][2]=(1-q)*inv(1-p*q%mod)%mod; t1[2][2]=q*(1-p)%mod*inv(1-p*q%mod)%mod;
		t2[1][1]=(1-p)*q%mod*inv(1-(1-p)*(1-q)%mod)%mod; t2[2][1]=p*inv(1-(1-p)*(1-q)%mod)%mod;
		t2[1][2]=q*inv(1-(1-p)*(1-q)%mod)%mod; t2[2][2]=(1-q)*p%mod*inv(1-(1-p)*(1-q)%mod)%mod;
		if (n/2) mat=mat*qpow(t2*t1, n/2);
		if ((n+1)/2-n/2) mat=mat*t2;
		printf("%lld\n", (mat[1][1]%mod+mod)%mod);
	}

	return 0;
}
posted @ 2021-10-12 06:26  Administrator-09  阅读(1)  评论(0编辑  收藏  举报