CF1761D

考虑设 f(i) 表示从低到高第 i 位的进位情况,0 表示不进位,1 表示进位。

分类讨论一下:

  • f(i1)=f(i)=1,那么 a,b 这一位有三种情况 (1,1),(1,0),(0,1)
  • f(i1)=f(i)=0,那么 a,b 这一位有三种情况 (0,0),(1,0),(0,1)
  • f(i1)=1,f(i)=0,那么 a,b 这一位有一种情况 (0,0)
  • f(i1)=0,f(i)=1,那么 a,b 这一位有一种情况 (1,1)

于是发现 f(i)=f(i1) 要乘 3,否则不变。

设总共有 n+1 位,并强制 f(0)=0

枚举有 x 个位置满足 f(i)f(i1),那么总共有 x+101 连续段,其中 0 的连续段有 x+12 个,1 的连续段有 x+12 个。

由于要填 k1,所以要填 n+1k0

而把 x 个元素分成 y 段的方案数,经典的隔板法,是 (x1y1)

于是总的式子是

ni=13ni×((n+1k)1i+121)×(k1i+121)

记得特判 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;
}
posted @   Kobe303  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示