Educational Codeforces Round 83 --- F. AND Segments

解法

根据题意,就是拆位,每一位上有两种限制,在[l,r]上全1或者存在0。
那我们考虑对每一位单独操作,f[i][j]表示处理了前i个位置,上次出现0是在j位置。
对于每一个可以放0的位置,\(f[i][i]=\sum_{j=1}^{i-1} f[i-1][j]\)
对于每个位置r,如果存在限制[l,r]存在0,那么\(f[r][1\sim l-1]\)就都会remove成0,成为非法情况
最后每位\(Ans=\sum_{i=0}^n f[n][i]\)
如果暴力做的话每一位是\(n^{2}\)
但是我们考虑,每次remove操作是有后延性的,我们可以同时进行,不用暴力清除\(1\sim l-1\)
这样额外记录一个\(sum=\sum_{j=1}^{i} f[i][j]\)就可以了

#include <bits/stdc++.h>
#define ll long long
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;

const ll mol = 998244353;
const int maxn = 5e5;

int to[maxn + 11],l[maxn + 11],r[maxn + 11],x[maxn + 11],a[maxn + 11];
ll f[maxn + 11];

ll sub(ll a,ll b) { a -= b; if (a < 0) a += mol; return a; }

int main(){
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n,k,m; cin >> n >> k >> m;
	for (int i = 1; i <= m; i++) {
		cin >> l[i] >> r[i] >> x[i];
	}
	ll ans = 1;
	for (int j = 0; j < k; j++) {
		for (int i = 1; i <= n; i++) a[i] = 0,to[i] = 0;
		for (int i = 1; i <= m; i++) {
			if (x[i] & (1 << j)) {
				a[l[i]]++; a[r[i] + 1]--;
			}
			else to[r[i]] = max(to[r[i]] , l[i]);
		}
		ll sum = 1;
		f[0] = 1;
		int ind = 0;
		for (int i = 1; i <= n; i++) {
			a[i] += a[i - 1];
			if (a[i]) f[i] = 0;
			else{
				f[i] = sum;
				sum = sum * 2 % mol;
			}
			if (!to[i]) continue;
			while (ind < to[i]) { sum = sub(sum , f[ind]); ind++; }
		}
		ans = ans * sum % mol;
	}
	cout << ans << endl;
	
} 

猜你喜欢

转载自www.cnblogs.com/Embiid/p/12564201.html