『数位DP及其优化』CF1327F AND Segments

P r o b l e m \mathrm{Problem} Problem

题目描述

你有三个整数 n , k , m n, k, m n,k,m 以及 m m m 个限制 ( l 1 , r 1 , x 1 ) , ( l 2 , r 2 , x 2 ) , … , ( l m , r m , x m ) (l_1, r_1, x_1), (l_2, r_2, x_2), \ldots, (l_m, r_m, x_m) (l1,r1,x1),(l2,r2,x2),,(lm,rm,xm)

计算满足下列条件的,长度为 n n n 的序列 a a a 的个数:

  • 对于每个 1 ≤ i ≤ n 1 \le i \le n 1in 0 ≤ a i < 2 k 0 \le a_i \lt 2 ^ k 0ai<2k
  • 对于每个 1 ≤ i ≤ m 1 \le i \le m 1im,数字的按位与 a [ l i ]  and  a [ l i + 1 ]  and  …  and  a [ r i ] = x i a[l_i] \text{ and } a_[l_i + 1] \text{ and } \ldots \text{ and } a[r_i] = x_i a[li] and a[li+1] and  and a[ri]=xi

两个序列 a , b a, b a,b 被认为是不同的,当且仅当存在一个位置 i i i 满足 a i ≠ b i a_i \neq b_i ai=bi

由于答案可能过大,请输出其对 998   244   353 998\ 244\ 353 998 244 353 取模的结果。

输入格式

第一行输入三个整数 n , k , m   ( 1 ≤ n ≤ 5 ⋅ 1 0 5 ; 1 ≤ k ≤ 30 ; 0 ≤ m ≤ 5 ⋅ 1 0 5 )   n, k, m ~(1 \le n \le 5 \cdot 10 ^ 5; 1 \le k \le 30; 0 \le m \le 5 \cdot 10 ^ 5)~ n,k,m (1n5105;1k30;0m5105) ,分别表示数组 a a a 的长度, a a a 中元素的值域,以及限制的个数。

接下来 m m m 行,每行描述一个限制 l i , r i , x i   ( 1 ≤ l i ≤ r i ≤ n ; 0 ≤ x i < 2 k ) l_i, r_i, x_i ~ (1 \le l_i \le r_i \le n; 0 \le x_i \lt 2 ^ k) li,ri,xi (1lirin;0xi<2k),分别表示限制的线段区间以及按位与值。

输出格式

输出一行一个整数,表示满足条件的序列 a a a 的个数,对 998   244   353 998\ 244\ 353 998 244 353 取模的结果。

说明/提示

你可以在 这里 获得有关按位与的信息。

在一个样例中,合法的序列 a a a 有: [ 3 , 3 , 7 , 6 ] [3, 3, 7, 6] [3,3,7,6] [ 3 , 7 , 7 , 6 ] [3, 7, 7, 6] [3,7,7,6] 以及 [ 7 , 3 , 7 , 6 ] [7, 3, 7, 6] [7,3,7,6]


S o l u t i o n \mathrm{Solution} Solution

这个题我们首先按位考虑,把问题转化为了:

  • 一个长度为 n n n 01 01 01 序列,给定两种限定:一种是区间内全部为 1 1 1,另一种是区间内至少有一个 0 0 0,问题有多少个合法的符合符合上述方案。

考虑上述两种方案,显然前者只需要直接赋值即可。

对于第二种限制,发现对于当前节点 i i i 来说,如果选取的时 0 0 0,设上一次选取 0 0 0 的位置为 j j j,那么一定需要保证不存在第二种区间 [ l , r ] [l,r] [l,r]满足 j < l ≤ r < i j<l\le r<i j<lr<i。因此我们得到结论:

  • 当第 i i i 个位置被钦定为 0 0 0 后,上一个 0 0 0 的位置 j j j 必须大于右端点小于 i i i 的任意左端点。即,对于任意取件 r i < i r_i<i ri<i j j j 至少为 min ⁡ { l i + 1 } \min\{l_i+1\} min{li+1}

由于这是计数题,难以考虑组合数的方法,我们考虑DP。

f i f_i fi表示到第 i i i 个位置,且当前位置一定为 0 0 0 的方案数。

  • a i = 1 a_i=1 ai=1时,强制 f i = 0 f_i=0 fi=0
  • 找到满足条件的最小 j j j f i = ∑ f j f_i=\sum f_j fi=fj

考虑优化,我们发现累加的 j j j 一个连续的区间,我们直接用前缀和优化即可。

现在我们的问题转化为了如何求解 j j j 的限制范围。

很妙的方法就是:

L[r[i]] = L[i];
for i = 1 - n : L[i]= max(L[i-1], L[i]).

C o d e \mathrm{Code} Code

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 6e5;
const int P = 998244353;

int n, m, k;
int s[N], Lmax[N], f[N], l[N], r[N], x[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (c < '0' || c > '9') w |= c == '-', c = getchar();
	while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

int calc(int t)
{
	for (int i=1;i<=n;++i) s[i] = Lmax[i] = f[i] = 0;
	for (int i=1;i<=m;++i) {
		if ((x[i] >> t) & 1) s[l[i]] ++, s[r[i] + 1] --;
		else Lmax[r[i]] = max(Lmax[r[i]], l[i]);
	}
	for (int i=1;i<=n+1;++i) {
		s[i] += s[i-1];
		Lmax[i] = max(Lmax[i-1], Lmax[i]);
	}
	int sum = 1, j = 0; f[0] = 1;
	for (int i=1;i<=n+1;++i)
	{
		if (s[i] > 0) { f[i] = 0; continue; }
		while (j < Lmax[i-1]) sum = (sum - f[j]) % P, j ++;
		f[i] = sum, sum = (sum + f[i]) % P;
	}
	f[n+1] = (f[n+1] % P + P) % P;
	return f[n+1];
}

signed main(void)
{
	n = read(), k = read(), m = read();
	for (int i=1;i<=m;++i) {
		l[i] = read();
		r[i] = read();
		x[i] = read();
	}
	int res = 1;
	for (int i=0;i<k;++i) res = res * calc(i) % P;
	cout << res << endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值