P11655「FAOI-R5」Lovely 139
题目背景
Update:数据有 0 0
,答案为 1
,请选手特判以正常通过。
Height ≤ 139 \text{Height}\leq139 Height≤139。
题目描述
对于一个 01 \tt 01 01 串 S S S(下标从 1 1 1 开始),我们定义它的一个区间 [ l , r ] [l,r] [l,r] 是极长颜色段,当且仅当它同时满足以下条件:
- 如果 l ≠ 1 l\neq 1 l=1, S l − 1 ≠ S l S_{l-1}\neq S_l Sl−1=Sl;
- 如果 r ≠ ∣ S ∣ r\neq \lvert S\rvert r=∣S∣, S r + 1 ≠ S r S_{r+1}\neq S_r Sr+1=Sr;
- ∀ i ∈ [ l , r ) , S i = S i + 1 \forall i\in[l,r),S_i=S_{i+1} ∀i∈[l,r),Si=Si+1。
定义 g ( S ) g(S) g(S) 为 S S S 的不同极长颜色段数。比如 g ( g( g( 00 \tt00 00 ) = 1 )=1 )=1, g ( g( g( 1110 \tt1110 1110 ) = 2 )=2 )=2, g ( g( g( 001011 \tt001011 001011 ) = 4 )=4 )=4。
定义 f ( n , m ) f(n,m) f(n,m) 的值为所有恰好包含 n \boldsymbol n n 个 0 \tt 0 0 和 m \boldsymbol m m 个 1 \tt 1 1 的 01 \tt 01 01 串 S S S 的 g ( S ) g(S) g(S) 之和。
你需要回答 T T T 个问题,每次给出 n , m n,m n,m 的值,求 f ( n , m ) f(n,m) f(n,m) 的值对 1 0 9 + 7 10^9+7 109+7 取模后的结果。
输入格式
第一行输入一个正整数数 T T T,表示问题个数。
接下来 T T T 行,每行两个非负整数 n , m n,m n,m,表示问题的参数。
输出格式
输出 T T T 行,每行为对应问题的答案。
样例 #1
样例输入 #1
3
2 2
4 6
7 8
样例输出 #1
18
1218
54483
样例 #2
样例输入 #2
3
845 826
672 826
618 925
样例输出 #2
789284214
588160420
730993180
样例 #3
样例输入 #3
1
1 46
样例输出 #3
139
提示
样例 1 解释
对于第一组数据 n = 2 , m = 2 n=2,m=2 n=2,m=2,一共有六个本质不同的 S S S,答案为 g ( g( g( 0011 \tt0011 0011 ) + g ( )+g( )+g( 0101 \tt0101 0101 ) + g ( )+g( )+g( 0110 \tt0110 0110 ) + g ( )+g( )+g( 1001 \tt1001 1001 ) + g ( )+g( )+g( 1010 \tt1010 1010 ) + g ( )+g( )+g( 1100 \tt1100 1100 ) = 2 + 4 + 3 + 3 + 4 + 2 = 18 )=2+4+3+3+4+2=18 )=2+4+3+3+4+2=18。
数据规模与约定
本题采用捆绑测试。
- Subtask 1(15 pts): 0 ≤ n + m ≤ 20 0 \le n+m \le 20 0≤n+m≤20, 1 ≤ T ≤ 10 1 \le T \le 10 1≤T≤10。
- Subtask 2(25 pts): 0 ≤ n + m ≤ 4 × 1 0 3 0 \le n+m \le 4 \times 10^3 0≤n+m≤4×103。
- Subtask 3(20 pts): 1 ≤ T ≤ 10 1 \le T \le 10 1≤T≤10。
- Subtask 4(40 pts):无特殊限制。
对于所有数据,保证 1 ≤ T ≤ 1 0 6 1 \leq T \leq 10^6 1≤T≤106, 0 ≤ n + m ≤ 2 × 1 0 6 0 \leq n+m\leq 2 \times 10^6 0≤n+m≤2×106, 0 ≤ n , m ≤ 2 × 1 0 6 0\le n,m\le 2\times10^6 0≤n,m≤2×106。
题解思路
问题描述
给定一个包含 n n n 个 0
和 $m个
1的
01` 串 S S S,定义 g ( S ) g(S) g(S) 为 S S S 的不同极长颜色段数。极长颜色段 [ l , r ] [l, r] [l,r] 需要满足以下条件:
- 如果 l ≠ 1 l \neq 1 l=1,则 S l − 1 ≠ S l S_{l-1} \neq S_l Sl−1=Sl;
- 如果 r ≠ ∣ S ∣ r \neq |S| r=∣S∣,则 S r + 1 ≠ S r S_{r+1} \neq S_r Sr+1=Sr;
- 对于所有 i ∈ [ l , r ) i \in [l, r) i∈[l,r), S i = S i + 1 S_i = S_{i+1} Si=Si+1。
定义 f ( n , m ) f(n, m) f(n,m) 为所有满足条件的 01
串 S S S 的 g ( S ) g(S) g(S) 之和,需要对 1 0 9 + 7 10^9 + 7 109+7 取模。
解题思路
1. 计算 g ( S ) g(S) g(S) 的贡献
对于任意一个 01
串 S S S, g ( S ) g(S) g(S) 可以通过以下方式计算:
- g ( S ) g(S) g(S) 等于 S S S 中满足 S i ≠ S i − 1 S_i \neq S_{i-1} Si=Si−1 的位置 i i i 的数量,再加上 1 1 1。
2. 贡献分解
将 f ( n , m ) f(n, m) f(n,m) 的贡献分解为两部分:
- 基础的贡献:每个
01
串 S S S 的基础贡献为 1 1 1,因为 g ( S ) g(S) g(S) 至少包含一个极长颜色段。总共有 ( n + m n ) \binom{n + m}{n} (nn+m) 个01
串,因此这部分的总贡献为:
( n + m n ) \binom{n + m}{n} (nn+m) - 变化的贡献:对于每个位置 i i i,如果 S i ≠ S i − 1 S_i \neq S_{i-1} Si=Si−1,则会对 g ( S ) g(S) g(S) 产生额外的贡献。对于每个位置 i i i, S i − 1 S_{i-1} Si−1 和 S i S_i Si 可以是
01
或10
,其余 ∣ S ∣ − 2 |S| - 2 ∣S∣−2 个位置可以任意排列。因此,每个位置 i i i 的贡献为:
2 × ( n + m − 2 n − 1 ) 2 \times \binom{n + m - 2}{n - 1} 2×(n−1n+m−2)
由于总共有 n + m − 1 n + m - 1 n+m−1 个可能的位置 i i i,因此这部分的总贡献为:
( n + m − 1 ) × 2 × ( n + m − 2 n − 1 ) (n + m - 1) \times 2 \times \binom{n + m - 2}{n - 1} (n+m−1)×2×(n−1n+m−2)
3. 总贡献
将两部分贡献相加,得到 f ( n , m ) f(n, m) f(n,m) 的表达式:
f ( n , m ) = ( n + m n ) + ( n + m − 1 ) × 2 × ( n + m − 2 n − 1 ) f(n, m) = \binom{n + m}{n} + (n + m - 1) \times 2 \times \binom{n + m - 2}{n - 1} f(n,m)=(nn+m)+(n+m−1)×2×(n−1n+m−2)
4. 模运算
由于结果需要对 1 0 9 + 7 10^9 + 7 109+7 取模,因此在计算组合数时需要使用模运算和预处理阶乘及其逆元来高效计算组合数。
总结
通过将 f ( n , m ) f(n, m) f(n,m) 的贡献分解为基础贡献和变化贡献,并利用组合数学的知识,可以高效地计算出 f ( n , m ) f(n, m) f(n,m) 的值。最终的结果需要对 1 0 9 + 7 10^9 + 7 109+7 取模,以确保结果的正确性。
代码:
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;const int MAX = 2000000 + 10; // 2e6 + 10
long long fact[MAX], inv_fact[MAX];long long qpow(long long a, long long b) { // 快速幂long long res = 1;while (b > 0) {if (b & 1)res = res * a % MOD;a = a * a % MOD;b >>= 1;}return res;
}void precompute() { // 预处理阶乘和阶乘逆元fact[0] = 1;for (int i = 1; i < MAX; ++i) {fact[i] = fact[i - 1] * i % MOD;}inv_fact[MAX - 1] = qpow(fact[MAX - 1], MOD - 2);for (int i = MAX - 2; i >= 0; --i) {inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;}
}long long comb(int a, int b) { // 计算组合数if (b < 0 || b > a)return 0;return fact[a] * inv_fact[b] % MOD * inv_fact[a - b] % MOD;
}void solve() {int n, m;cin >> n >> m;if (n == 0 || m == 0) {printf("1\n");return;}int a = n + m;int term1 = (a - 1) * 2 % MOD;term1 = term1 * comb(a - 2, n - 1) % MOD;int term2 = comb(a, n) % MOD;int ans = (term1 + term2) % MOD;cout << ans << endl;
}signed main() {cin.tie(0)->ios::sync_with_stdio(0);precompute();int T = 1;cin >> T;while (T--) {solve();}return 0;
}