[11.07]模拟赛T1

题目描述

小修和小栋在玩一个叫做先发制人的抛硬币游戏。
游戏双方轮流掷一枚硬币至正面朝上或者朝下,规定谁先掷出正面朝上为赢。
前一场的输者,则下一场先掷.若第一场小修先扔,则小修赢得第 n 场的概率是多少。

输入

一行两个整数n。

输出

假设小修赢得第 n 场的概率是 P, 输出 P 在模 998244353 意义下的值。

样例

样例输入

1

样例输出

665496236

解释:P = 2 3 \frac{2}{3} 32

数据说明与提示

对于50% 的数据, 1 ≤ n ≤ 105
对于 100% 的数据,1 ≤ n ≤ 109。

说实话,对于n=1时P= 2 3 \frac{2}{3} 32考场上真是让我苦恼了一会儿。
刚开始没推出来,然后就去看后两道,发现也不会,然后,小水一会儿就去演草纸上写《阿房宫赋》了。
也挺神奇的,写着写着就有点思路了。
所以我们先推n=1。
我们先考虑一轮,
小阳有 1 2 \frac{1}{2} 21正和 1 2 \frac{1}{2} 21
小修有 1 2 \frac{1}{2} 21正和 1 2 \frac{1}{2} 21
我们把这几种情况两两组合
用Y代表小阳,X代表小修,1代表正,0代表下
那么有四种情况
1Y 1X , 1Y 0X
0Y 1X , 0Y 0X
这里对于 0Y 0 X 的情况我们可以忽略,因为两个人都没有翻到正面,就会重新进行一轮直到不是这个结果。
所以一共有三种情况,其中两种都是小阳胜,一种小修胜所以P = 2 3 \frac{2}{3} 32
那么我们考虑n>1的情况,
事实上,我们只要求第n场赢,所以n-1场以及前面的场次赢或不赢我们只关心它对先后手的影响,
f i , 1 f_{i,1} fi,1表示第i场先手赢的概率 f i , 0 f_{i,0} fi,0表示第i场先手输的概率
那么先手赢的话会交换先后手,输的话不会,
我们又知道一场的先后手获胜的概率
所以可以得到递推式 f i , 1 = f ( i − 1 ) , 1 ∗ 1 3 + f ( i − 1 ) , 0 ∗ 2 3 f_{i,1} = f_{(i-1), 1} * \frac{1}{3} + f_{(i-1), 0} * \frac{2}{3} fi,1=f(i1),131+f(i1),032
不过显然这样我们不能过全部的数据。
我们可以考虑推通项公式,这里有一个更直接的规律,就不推通项公式了
我们考虑列出几项
胜: 2 3 \frac{2}{3} 32 __ 4 9 \frac{4}{9} 94 __ 14 27 \frac{14}{27} 2714 __ 40 81 \frac{40}{81} 8140

负: 1 3 \frac{1}{3} 31 __ 5 9 \frac{5}{9} 95 __ 13 27 \frac{13}{27} 2713 __ 41 81 \frac{41}{81} 8141
____1___2____3____4
我们会发现一些有趣的性质,
分母是3n
当n为奇数时: 分子是 3 n > > 1 ∣ 1 3^n>> 1 | 1 3n>>11
当n为偶数时:分子是 3 n > > 1 3^n>>1 3n>>1
除二的操作不用处理成逆元,分母处理成逆元就好了
C o d e Code Code

#include

#define ll long long
#define MAXN 5000100
#define N 1001
#define INF 0x3f3f3f3f
#define gtc() getchar()

using namespace std;

template <class T>
inline void read(T &s){
	s = 0; T w = 1, ch = gtc();
	while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
	while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
	s *= w;
}

template <class T>
inline void write(T x){
    if(x < 0) putchar('-'), x = -x;
	if(x > 9) write(x/10);
    putchar(x % 10 + '0');
}

const ll mod = 998244353;
ll mi (ll a, ll b){
	int cnt = 1;
	for(; b; b >>= 1){
		if(b & 1) cnt = (cnt * a) % mod;
		a = (a * a) % mod;
	}
	return cnt % mod;
}

ll f[MAXN][2];
int n;

int main()
{
//	freopen("coin.in", "r", stdin);
//	freopen("coin.out", "w", stdout);
	read(n);
	if(n <= 100000){
		f[1][1] = (2 * mi(3, mod - 2)) % mod;
		f[1][0] = mi(3, mod-2); 
		for(int i = 2; i <= n; ++i){
			f[i][1] = ((f[i-1][1] % mod * f[1][0] % mod) % mod + (f[i-1][0] % mod * f[1][1] % mod) % mod) % mod;
			f[i][0] = (1 - f[i][1] + mod) % mod;	
			}
		cout << f[n][1] << endl;
	} 
	else {
		ll res = mi(3, n);
		if(n & 1){
			cout << ((res/2 + 1) % mod * mi(res, mod -2) % mod ) % mod;
		}
		else {
			cout << ((res/2) % mod * mi(res, mod - 2) % mod) % mod;
		}
	}
	return 0;
}

你可能感兴趣的:(数论)