day17T1改错记

题目描述

原题AGC015E

给出(n)条不与(y)轴平行的直线(y = k_ix + b_i),现在要把它们染色

如果两条直线(l1, l2)(y)轴右侧有交点,那么染色(l1)将同时造成(l2)被染色,染色(l2)将同时造成(l1)被染色,并且影响可以传递((l_1)染色(l_2)(l_2)又染色(l_3)……)

初始你可以选定某些直线染色,然后根据上面的规则可能会有更多直线被染色

问有多少种初始的选择方案,使得最后所有直线被染色?答案对(1e9 + 7)取模

(1 le N le 5e5, |k_i|, |b_i| le 1e9, 保证b_i互不相同)

解析

如果(k_i < k_j, b_i > b_j),那么染色(i)必定造成(j)被染色,(k_i > k_j, b_i < b_j)同理

然后根据染色的“传递性”,可以发现如果把所有直线按(k)排序,染色(i)会造成([L_i, R_i])区间内的直线被染色

其中(L_i)是排序后在(i)前面,最远的那条(b)(i)大的直线;(R_i)是排序后在(i)后面,最远的那条(b)(i)小的直线;

(L_i)(R_i)可以借助树状数组处理出来

然后问题就变成了给出(n)个区间,有多少种方案使得([1, n])都被覆盖

然后因为这个题的区间不会出现完全包含((L_i < L_j le R_j < R_i))的情况,所以可以(dp)+前缀和优化(并不知道存在包含的情况可不可以),这一部分具体见代码(如果像我一样以前没见过,手推几组数据大概就理解了……)

然后就没有然后了……

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define MAXN 500005

typedef long long LL;
const int mod = (int)1e9 + 7;
const int inf = 0x3f3f3f3f;

struct Line {
	int k, b;
	bool operator <(const Line &l) const { return k == l.k ? b < l.b : k < l.k; }
};
struct Interval {
	int l, r;
	bool operator <(const Interval &i) const { return l == i.l ? r < i.r : l < i.l; }
};

char gc();
int read();
void prework();
void DP();
int query1(int);
int query2(int);
void update1(int, int);
void update2(int, int);

Line ln[MAXN];
Interval inter[MAXN];
int N, table[MAXN], tot, tree[MAXN], ans;

inline void inc(int &x, int y) { x += y; if (x >= mod) x -= mod; }
inline void dec(int &x, int y) { x -= y; if (x < 0) x += mod; }
inline int add(int x, int y) { x += y; return x >= mod ? x - mod : x; }
inline int sub(int x, int y) { x -= y; return x < 0 ? x + mod : x; }

int main() {
	freopen("river.in", "r", stdin);
	freopen("river.out", "w", stdout);

	N = read();
	for (int i = 1; i <= N; ++i)
		ln[i].b = read(), ln[i].k = read();
	prework();
	DP();
	printf("%d
", ans);
}
inline char gc() {
	static char buf[1000000], *p1, *p2;
	if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
	return p1 == p2 ? EOF : *p2++;
}
inline int read() {
	int res = 0, op; char ch = gc();
	while (ch != '-' && (ch < '0' || ch > '9')) ch = gc();
	op = (ch == '-' ? ch = gc(), -1 : 1);
	while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
	return res * op;
}
void prework() {
	for (int i = 1; i <= N; ++i) table[i - 1] = ln[i].b;
	std::sort(table, table + N);
	tot = std::unique(table, table + N) - table;
	for (int i = 1; i <= N; ++i) ln[i].b = std::lower_bound(table, table + N, ln[i].b) - table + 1;
	std::sort(ln + 1, ln + N + 1);
	memset(tree, inf, sizeof tree);
	for (int i = 1; i <= N; ++i) {
		update1(ln[i].b, i);
		inter[i].l = query1(ln[i].b);
	}
	memset(tree, 0, sizeof tree);
	for (int i = N; i; --i) {
		update2(ln[i].b, i);
		inter[i].r = query2(ln[i].b);
	}
	std::sort(inter + 1, inter + N + 1);
}
void update1(int p, int v) {
	for (int i = p; i; i -= (i & -i))
		tree[i] = std::min(tree[i], v);
}
void update2(int p, int v) {
	for (int i = p; i <= tot; i += (i & -i))
		tree[i] = std::max(tree[i], v);
}
int query1(int p) {
	int res = inf;
	for (int i = p; i <= tot; i += (i & -i))
		res = std::min(res, tree[i]);
	return res;
}
int query2(int p) {
	int res = 0;
	for (int i = p; i; i -= (i & -i))
		res = std::max(res, tree[i]);
	return res;
}
void DP() {
	static int f[MAXN], s[MAXN];
	for (int i = 1, j = 1; i <= N; ++i) {
		while (inter[j].r < inter[i].l - 1) ++j;
		f[i] = sub(s[i - 1], s[j - 1]);
		if (inter[i].l == 1) inc(f[i], 1);
		if (inter[i].r == N) inc(ans, f[i]);
		s[i] = add(s[i - 1], f[i]);
	}
}
//Rhein_E 100pts
原文地址:https://www.cnblogs.com/Rhein-E/p/10566779.html