\(\text{Solution}\)
容易发现其实就是将长度为 \(n\) 的区间划分成若干奇数段的总方案数再除以 \(2^n\)。
解释一下就是因为每个小镇选与不选的概率都是 \(\frac{1}{2}\),那么每种方案的概率都是一样的。
我们发现 \(0,n+1\) 不能收到信号其实就是将 \([1,n]\) 阻断起来,很容易联想到 \(\text{DP}\) 的子状态:\(f[i]\) 表示 \(i\) 个小镇的总方案数,那我们就有转移柿(枚举最后一段长度为 \(2\times j+1\),\(f[0]=0\)):
- 若 \(i\) 为偶数:
\[f[i]=\sum_{j=0}^{\frac{i-1}{2}} f[i-2\times j-1]
\]
- 若 \(i\) 为奇数(加 \(1\) 是因为本身可以成为一种长度为 \(i\) 方案):
\[f[i]=1+\sum_{j=0}^{\frac{i-1}{2}} f[i-2\times j-1]
\]
这个时候就可以分奇偶做前缀和优化以 \(\mathcal O(n)\) 的优秀复杂度通过此题。
但其实这个柿子暗藏玄机,其实 \(f[n]\) 就是 \(\text{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\)。
\(\text{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,'\n');
return 0;
}