ARC065 简要题解
ARC065 简要题解
A
从前往后不好做, 那就直接从后往前
B
考虑设 \(f[i][j]\) 为在第一张图中属于 \(i\) 集合, 在第二张图中属于 \(j\) 集合的点的个数
这样会 MLE , 但是又发现有用的 \((i, j)\) 不会很多, 直接 \(map\) 存下来就行了
C
转化为切比雪夫距离之后直接从起点 bfs , 把横纵坐标离散化之后存在 set 中, 找到一个就删掉他, 这样就可以保证 bfs 的复杂度是对的了
然后对于每个点算一次贡献
发现一个点对会算两次, 最后把答案除以二就行了
D
互相包含的区间是没有用的, 证明的话考虑把小的那个区间挖出去
然后就可以把所有的区间变成左端点和右端点都单调递增的区间了
那么一个区间控制的范围就是他的左端点到 min(他的右端点, 下一个区间的左端点 - 1)
设 \(f[i][j]\) 为前 \(i\) 个点控制的范围中放置了 \(j\) 个 1 并且合法的方案
枚举一个 \(k\) 然后从 \(f[i - 1][j - k]\) 转移过来, 乘个组合数就行了
复杂度 \(O(n^3)\) , 但根据网上题解的说法, 复杂度是 \(O(n ^ 2)\) 的
有点没讲清楚细节, 放下代码吧
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 3e3 + 5;
const int mod = 1e9 + 7;
using namespace std;
int n, m, a[N], l[N], r[N], vis[N], sum[N], c[N][N], f[N][N], mx[N], len[N];
struct node
{
int l, r;
bool operator < (const node &p) const
{
return l == p.l ? r > p.r : l < p.l;
}
} p[N];
char s[N];
template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
n = read <int> (), m = read <int> (), scanf("%s", s + 1);
for(int i = 1; i <= n; i++) a[i] = s[i] - '0';
for(int i = 1; i <= m; i++) p[i].l = read <int> (), p[i].r = read <int> ();
for(int i = 1; i <= m; i++)
for(int j = p[i].l; j <= p[i].r; j++) vis[j] = 1;
sort(p + 1, p + m + 1); int tmp = m; m = 0;
for(int x = 0, i = 1; i <= tmp; i++)
if(p[i].r > x) x = p[i].r, p[++m] = p[i];
p[m + 1].l = n * 2;
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + vis[i] * a[i];
for(int i = 1; i <= m; i++) mx[i] = sum[p[i].r];
for(int i = 1; i <= m; i++) l[i] = p[i].l, r[i] = min(p[i + 1].l - 1, p[i].r), len[i] = len[i - 1] + r[i] - l[i] + 1;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= i; j++)
c[i][j] = (!j ? 1 : (c[i - 1][j - 1] + c[i - 1][j]) % mod);
f[0][0] = 1;
for(int i = 1; i <= m; i++)
for(int j = 0; j <= mx[i - 1]; j++)
for(int k = 0; k <= mx[i] - j; k++)
{
if((mx[i] - j - k) > p[i].r - r[i] || (p[i].r - r[i] + j + k - mx[i]) > p[i].r - r[i]) continue;
f[i][j + k] = (1ll * c[r[i] - l[i] + 1][k] * f[i - 1][j] + f[i][j + k]) % mod;
}
printf("%d\n", f[m][sum[n]]);
return 0;
}