You are god again!|

definieren

园龄:3年粉丝:7关注:4

2023-11-11 19:22阅读: 12评论: 0推荐: 0

[题解] CF1327F AND Segments

AND Segments

m 个限制 (l,r,x)
要计算满足以下条件的长度为 n 的序列 a 的数量:

  • i[1,n],0ai<2k
  • i[1,m],aliandali+1andandari=x
    n,m105,k30

首先要想到分别计算二进制下每一位的方案数然后乘起来就是答案。

然后现在问题就变成了有若干个限制表示 a[li,ri] 中的数的按位与为 0/1,要计算 01 序列 a 的数量。

将每个限制挂到右端点上,然后 dp 计算方案数。

因为是按位与,所以值只与最后一个 0 的位置有关。所以设 fi,j 表示考虑了前 i 个位置,最后一个 0 的位置为 j 时的方案数。

可以发现,对于每条限制,其实是限制了最后一个 0 的位置一定是在一个区间里。具体地说,如果有一个限制 (l,r,0),就说明在 [l,r] 一定有一个 0,也就是当 i=r 时,最后一个 0 一定是在 [l,r] 中;如果有一个限制 (l,r,1),就说明在 [l,r] 中一定全是 1,也就是当 i=r 时,最后一个 0 一定是在 [0,l1] 中。

转移就是先考虑没有限制的时候:对当前位置填 0 还是填 1 分别考虑:

fi,jfi1,jfi,ij[0,i)fi1,j

再考虑加上限制:

  • 如果有一个限制 (l,r,0)

j[0,l),fr,j=0

  • 如果有一个限制 (l,r,1)

i[l,r],fi,i=0

把第一维滚掉之后我们要做的就是单点改、前缀推平成 0、求前缀和,这个记一下前缀和和最长前缀推平长度就行了。

时间复杂度 O(nk)

constexpr int MAXN = 5e5 + 9;
int n, k, m, ans = 1, f[MAXN], a[MAXN];
vector<pair<int, int> > lim[MAXN];

int calc(int bit) {
	for (int i = f[0] = 1; i <= n; i ++) f[i] = 0, a[i] = 0;
	for (int r = 1; r <= n; r ++) for (auto [l, x] : lim[r])
		if (x >> bit & 1) a[l] ++, a[r + 1] --;
	for (int i = 1; i <= n; i ++) a[i] += a[i - 1];
	int sum = 1, pre = 0;
	for (int i = 1; i <= n; i ++) {
		int pos = 0;
		for (auto [l, x] : lim[i])
			if ((x >> bit & 1) == 0) cmax(pos, l);
		if (!a[i]) f[i] = sum, cadd(sum, f[i]);
		while (pre < pos) cdel(sum, f[pre]), pre ++;
	}
	return sum;
}

void slv() {
	n = Read<int>(), k = Read<int>(), m = Read<int>();
	for (int i = 1; i <= m; i ++) {
		int l = Read<int>(), r = Read<int>(), x = Read<int>();
		lim[r].emplace_back(l, x);
	}
	for (int i = 0; i < k; i ++) cmul(ans, calc(i));
	Write(ans, '\n');
	return;
}
posted @   definieren  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起