AGC045C

AGC045C Range Set

简单题。

显然初始全零和全一没有区别,可以全部进行一次覆盖,所以如果 $A>B$ 可以交换 $A,B$ 。

首先可以发现,如果打算在结尾放 $B$ 个 $1$ ,那么前面任意放的状态都可以被构造出来。因为总是可以用 $A$ 个 $0$ 去覆盖掉一部分的 $1$ 。

接着考虑,会发现如果在序列中任意存在一段连续 $B$ 个 $1$ ,那么它的左右的构造是互不影响的,都可以用一样的方法造出来。所以只要序列中存在一段连续 $B$ 个 $1$ 就一定可以构造出来。

如果序列中不存在连续 $B$ 个 $1$ ,有时也是可以被构造出来的。可以发现,如果有一段长度大于等于 $A$ 的 $0$ 序列,它其实可以是在最后把这段从 $1$ 变成 $0$ 的,因此可以把它看成一段 $1$ 。

如果顺着这个思路去想,可以发现对于一段连续的长度大于等于 $B$ 的 $1$ ,其实也可以看作是在最后通过将一段 $0$ 变成 $1$ 得到的。所以如果倒着思考这个问题,只要存在一段长度大于等于 $B$ 的 $1$ ,它总是可以交替进行变 $0$ 和变 $1$ 并且最终将整个序列回滚成 $0$ ,所以是一定可以被构造出来的。

所以倒着考虑,一个序列是否合法就变成了在开始时可以将长度大于等于 $A$ 的连续 $0$ 段变成 $1$ ,问是否可以造出一段长度大于等于 $B$ 的连续 $1$ 段。

显然,考虑反面更容易,考虑计数不可被构造出来的序列个数。也就是即使将所有大于等于 $A$ 的 $0$ 段反转成 $1$ ,也无法在序列中凑出一个长度大于等于 $B$ 的段。也就是说任何两个长度小于 $A$ 的 $0$ 段的间隔必须小于 $B$ 。这个问题可以简单地用 dp 解决。

设 $dp[i][0/1]$ 表示当前考虑到序列的第 $i$ 个位置,最后一段放的是长度小于 $A$ 的 $0$ 段还是长度小于 $B$ 的 $1+0$ 段,随便转移一下即可。

复杂度 $O(n^2)$ 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "unordered_map"
#include "cassert"
#include "bitset"
#include "queue"
using namespace std;
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
//#pragma GCC optimize(3)
typedef long long ll;
const int MAXN = 5006;
const int P = 1e9 + 7;
int n , a , b;
int f[MAXN] , dp[MAXN][2];
void solve() {
cin >> n >> a >> b;
if( a > b ) swap( a , b );
f[0] = f[1] = 1;
rep( i , 2 , n ) {
f[i] = f[i - 1];
rep( j , 0 , i - a - 1 ) f[i] = ( f[i] + f[j] ) % P;
}
rep( i , 1 , a - 1 ) dp[i][0] = 1;
rep( i , 1 , b - 1 ) dp[i][1] = f[i];
rep( i , 1 , n ) {
rep( j , max( 1 , i - a + 1 ) , i - 1 ) dp[i][0] = ( dp[i][0] + dp[j][1] ) % P;
rep( j , max( 1 , i - b + 1 ) , i - 1 ) dp[i][1] = ( dp[i][1] + dp[j][0] * 1ll * f[i - j - 1] ) % P;
}
int ans = dp[n][0];
rep( i , n - b + 1 , n - 1 ) {
ans = ( ans + dp[i][0] * 1ll * f[n - i] ) % P;
}
int p2 = 1;
rep( i , 1 , n ) p2 = ( p2 + p2 ) % P;
cout << ( p2 + P - ans ) % P << endl;
}

signed main() {
// int T;cin >> T;while( T-- ) solve();
solve();
}

文章作者: yijan
文章链接: https://yijan.co/AGC045C/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog