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; 
}
posted @ 2020-09-05 21:49  ztlztl  阅读(142)  评论(0编辑  收藏  举报