CF1761D
考虑设 \(f(i)\) 表示从低到高第 \(i\) 位的进位情况,\(0\) 表示不进位,\(1\) 表示进位。
分类讨论一下:
- \(f(i-1)=f(i)=1\),那么 \(a,b\) 这一位有三种情况 \((1,1),(1,0),(0,1)\)。
- \(f(i-1)=f(i)=0\),那么 \(a,b\) 这一位有三种情况 \((0,0),(1,0),(0,1)\)。
- \(f(i-1)=1,f(i)=0\),那么 \(a,b\) 这一位有一种情况 \((0,0)\)。
- \(f(i-1)=0,f(i)=1\),那么 \(a,b\) 这一位有一种情况 \((1,1)\)。
于是发现 \(f(i)=f(i-1)\) 要乘 \(3\),否则不变。
设总共有 \(n+1\) 位,并强制 \(f(0)=0\)。
枚举有 \(x\) 个位置满足 \(f(i)\ne f(i-1)\),那么总共有 \(x+1\) 个 \(01\) 连续段,其中 \(0\) 的连续段有 $\left \lceil \dfrac{x+1}{2} \right \rceil $ 个,\(1\) 的连续段有 $\left \lfloor \dfrac{x+1}{2} \right \rfloor $ 个。
由于要填 \(k\) 个 \(1\),所以要填 \(n+1-k\) 个 \(0\)。
而把 \(x\) 个元素分成 \(y\) 段的方案数,经典的隔板法,是 \(\dbinom{x-1}{y-1}\)。
于是总的式子是
\[\sum_{i=1}^n 3^{n-i}\times \dbinom{(n+1-k)-1}{\left \lceil \dfrac{i+1}{2} \right \rceil -1}\times \dbinom{k-1}{\left \lfloor \dfrac{i+1}{2} \right \rfloor -1}
\]
记得特判 \(k=0\) 的情况。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000005, mod = 1e9 + 7;
int n, k;
int fac[N], inv[N], pw[N];
int ans;
int qpow(int x, int y) {
int res = 1;
while (y) {
if (y & 1) res = 1ll * res * x % mod;
x = 1ll * x * x % mod;
y >>= 1;
}
return res;
}
void init(int n) {
fac[0] = pw[0] = 1;
for (int i = 1; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % mod, pw[i] = 1ll * pw[i - 1] * 3 % mod;
inv[n] = qpow(fac[n], mod - 2);
for (int i = n - 1; ~i; --i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}
int C(int n, int m) {
if (n < 0 || m < 0 || n < m) return 0;
return 1ll * fac[n] * inv[n - m] % mod * inv[m] % mod;
}
void add(int &a, int b) {
a += b;
if (a >= mod) a -= mod;
}
int main() {
scanf("%d%d", &n, &k);
init(n);
if (!k) return printf("%d", pw[n]), 0;
for (int i = 1; i <= n; ++i) add(ans, 1ll * pw[n - i] * C(n + 1 - k - 1, ((i + 1) - (i + 1) / 2) - 1) % mod * C(k - 1, (i + 1) / 2 - 1) % mod);
printf("%d", ans);
return 0;
}