GMOJ7314. 【2021.10.21NOIP提高组模拟】咕(gu)

题目大意

image

解题思路

发现离散化之后一眼一个naive \(O(n^4)\) dp对吧,考虑优化这个东西。

其实就是对于一个相等的点对 \((i,j)\),你找到的是 \((p,q)\) 以转移,其中 \(p<i,q<j,S_i=T_j=c_1,S_p=T_q=c_2\),且有一条边 \(<c_2,c_1>\)

考虑边做边维护一个 \(g_j\) 表示 \(\sum\limits_{k<i}f_{i,j}\),再把所有能转移到 \(i\)\(q\) 的所有 \(g_q\) 加起来,就是 \(f_{i,j}\)了!

这个操作的本质是先对一维做了一个前缀和,然后对二维做了一个求和,实际上这种分维数做前缀和的操作挺适用于每一维都有限制的情况的,高维前缀和也是这个思想。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(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;
inline void read(int &x) {// ll, ne
	x = 0; char ch = getchar();
	while(ch < '0' || ch > '9')	ch = getchar();
	while(ch >= '0' && ch <= '9')	x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
}
const int N = 3e3 + 10, mod = 1e9 + 7;
int n, m, tot, k, a[N], b[N], g[N], f[N][N], t[N << 1], mp[N << 1][N << 1];
inline int find(int x) {int p = lower_bound(t + 1, t + tot + 1, x) - t; return t[p] == x ? p : 0;}
int main() {
	freopen("gu.in", "r", stdin);
	freopen("gu.out", "w", stdout);
	read(n), read(m), read(k);
	fo(i, 1, n)	read(a[i]), t[i] = a[i];
	fo(i, 1, m)	read(b[i]), t[i + n] = b[i];
	sort(t + 1, t + n + m + 1);
	tot = unique(t + 1, t + n + m + 1) - t - 1;
	fo(i, 1, n)	a[i] = find(a[i]);
	fo(i, 1, m)	b[i] = find(b[i]);
	int ans = 0;
	int u, v;
	fo(i, 1, k)
		read(u), u = find(u), read(v), v = find(v), mp[u][v] = 1;
	fo(i, 1, n) {
		int tmp = 0;
		fo(j, 1, m) {
			a[i] == b[j] && (f[i][j] = (tmp + 1) % mod, ans = (ans + f[i][j]) % mod);
			mp[b[j]][a[i]] && (tmp = (tmp + g[j]) % mod);
			a[i] == b[j] && (g[j] = (g[j] + f[i][j]) % mod);
		}
	}
	printf("%d\n", ans);
	return 0;
}

posted @ 2021-10-21 22:37  Martin_MHT  阅读(27)  评论(0)    收藏  举报