CodeForces

( ext{Solution})

容易发现其实就是将长度为 (n) 的区间划分成若干奇数段的总方案数再除以 (2^n)

解释一下就是因为每个小镇选与不选的概率都是 (frac{1}{2}),那么每种方案的概率都是一样的。

我们发现 (0,n+1) 不能收到信号其实就是将 ([1,n]) 阻断起来,很容易联想到 ( ext{DP}) 的子状态:(f[i]) 表示 (i) 个小镇的总方案数,那我们就有转移柿(枚举最后一段长度为 (2 imes j+1)(f[0]=0)):

  • (i) 为偶数:

[f[i]=sum_{j=0}^{frac{i-1}{2}} f[i-2 imes j-1] ]

  • (i) 为奇数(加 (1) 是因为本身可以成为一种长度为 (i) 方案):

[f[i]=1+sum_{j=0}^{frac{i-1}{2}} f[i-2 imes j-1] ]

这个时候就可以分奇偶做前缀和优化以 (mathcal O(n)) 的优秀复杂度通过此题。

但其实这个柿子暗藏玄机,其实 (f[n]) 就是 ( ext{Fib}[n])(针对数据思考)

首先 (f[1],f[2]) 肯定满足。

还是分奇偶讨论:

  • (n) 为偶数:

[f[n]=f[1]+f[3]+f[5]+...+f[n-1] ]

[=f[2]+f[3]+f[5]+...+f[n-1] ]

[=f[4]+f[5]+...+f[n-1] ]

[=f[n-2]+f[n-1] ]

  • (n) 为奇数:

[f[n]=1+f[2]+f[4]+...+f[n-1] ]

[=f[1]+f[2]+f[4]+...+f[n-1] ]

[=f[3]+f[4]+...+f[n-1] ]

[=f[n-2]+f[n-1] ]

(3) 开始我们这样递推地证明,可以一直推到 (n)

( ext{Code})

#include <cstdio>
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++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(T x) {
	if(x<0) return (void)(putchar('-'),write(-x));
	if(x>9) write(x/10);
	putchar(x%10^48);
}

#include <iostream>
using namespace std;

const int mod=998244353;

int n,a=1,b=1;

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;
}

int main() {
	n=read(9);
	rep(i,3,n) a=(a+b)%mod,swap(a,b);
	print(1ll*b*qkpow(qkpow(2,n),mod-2)%mod,'
');
	return 0;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/14083524.html