[AGC045C] Range Set
Genius_Star · · 题解
或许更好的阅读体验。
思路:
这种算最终能形成多少本质不同的东西,都是考虑倒着做,即给定一个字符串,判断它是否能被操作给表示出来。
这题也是一样,考虑怎么判定字符串
具体的,显然最后一次一定是连着的长为
所以本质上,判定
先钦定
-
如果剩下
0 且不能进行一次长为a 的覆盖,那么显然无解。 -
否则,设找到了一个
0 和? 的长为a 的覆盖是[l, r] ,那么显然,其可以从中间向两边拓展开来,把所有的都覆盖成? (因为a \ge b ,所以剩下的连续1 最多b - 1 个,一定可以通过中间覆盖过去的? 把这些1 改成? )。
所以有解当且仅当把长度
然后考虑怎么计数?显然对于长度
于是你的结构一定是
然后再定义
- 当
i 结尾是0 时,枚举j ,表示[i, j] 是一个<a 的“全0 段”,显然上一段结尾要是1 ,不然会和这段拼起来,且j 位置处也要是0 ,不然会和上一段结尾的1 拼起来(只有当j = 1 的时候没有限制,因为没有上一段),所以:
- 否则
i 结尾是1 时,枚举j ,表示[i, j] 是一个<b 的全1 段,显然上一段结尾要是0 ,不然会拼起来,所以:
最后答案怎么算,你发现直接
再定义对于一个长度为
顺便转移下
所以实际上答案是:
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define lowbit(x) (x) & (-(x))
#define popcnt(x) __builtin_popcount(x)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N = 5e3 + 10, mod = 1e9 + 7;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
inline void getadd(int &x, int y){
x = (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline int add(int x, int y){
return (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline void getdec(int &x, int y){
x = (x < y) ? (x - y + mod) : (x - y);
}
inline int dec(int x, int y){
return (x < y) ? (x - y + mod) : (x - y);
}
int n, a, b, ans;
int f[N], g[N][2], dp[N][N];
int main(){
n = read(), a = read(), b = read();
if(a < b)
swap(a, b);
f[0] = ans = 1;
for(int i = 1; i <= n; ++i){
ans = ans * 2ll % mod;
g[i][0] = f[i - 1];
for(int j = 1; j <= i - b + 1; ++j)
getadd(g[i][1], f[max(0, j - 2)]);
f[i] = add(g[i][0], g[i][1]);
// cerr << f[i] << '\n';
}
dp[0][0] = dp[0][1] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= i; ++j){
if(i - j + 1 < a)
getadd(dp[i][0], 1ll * f[max(i - j - (j > 1), 0)] * dp[j - 1][1] % mod);
if(i - j + 1 < b)
getadd(dp[i][1], dp[j - 1][0]);
}
}
getdec(ans, dp[n][0]);
getdec(ans, dp[n][1]);
for(int i = 1; i <= n; ++i)
if(n - i + 1 < a)
getdec(ans, 1ll * g[n - i + 1 - (i > 1)][1] * dp[i - 1][1] % mod);
write(ans);
return 0;
}