• 【题解】 CF1327F AND Segments dp+按位


    Legend

    Link ( extrm{to Codeforces})

    现有一个长 (n) 的数组 (a (0 le a < 2^k)),给定 (m) 个限制,形如 (l,r,x) 表示 (operatorname{AND}limits_{i=l}^{r} a_i=x)

    求出有多少个满足条件的数组。

    (1 le n le 5cdot 10^5)(0 le m le 5cdot 10^5)(1 le k le 30)

    Editorial

    容易发现位之间答案独立,最后只需要乘起来,问题转化为 (a_i,xin{0,1})

    对于 (x=1) 的限制,等价于直接确定了这个区间一定都是 (1)

    对于 (x=0) 的限制,说明这个区间至少有一个 (0)

    只有 (x=0) 的限制时,是个经典题。

    做法是设 (dp_i) 表示只考虑前 (i) 个位置,第 (i) 个位置放了 (0),使得区间左端点 (le i) 的区间全部满足要求的方案数量。

    转移就直接找可行的转移点(右端点 (<i) 的区间的最靠右的左端点以后的位置都可行),一定是连续的区间 (sum) 一下就行了。

    前缀和可以动态维护,做到 (O(1)) 转移。

    在此处有了 (x=1) 的限制则直接钦定这些地方的 (dp) 值为 (0) 即可。

    复杂度 (O(k(n+m)))

    Code

    #include <bits/stdc++.h>
    
    #define LL long long
    
    using namespace std;
    
    const LL MOD = 998244353;
    const int MX = 5e5 + 233;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    int n ,k ,m;
    struct segment{
    	int l ,r ,x;
    	bool operator <(const segment &B)const{
    		return r == B.r ? l > B.l : r < B.r;
    	}
    }s[MX];
    
    LL ban[MX] ,S[MX] ,dp[MX];
    LL solve(int bit){
    	for(int i = 1 ; i <= n + 1 ; ++i) ban[i] = 0;
    	for(int i = 1 ; i <= m ; ++i){
    		if((s[i].x >> bit) & 1){
    			ban[s[i].l]++;
    			ban[s[i].r + 1]--;
    		}
    	}
    	int sl = 1 ,lim = 0;
    	dp[0] = S[0] = 1;
    
    	for(int i = 1 ; i <= n + 1 ; ++i){
    		ban[i] += ban[i - 1];
    		
    		while(sl <= m && s[sl].r < i){
    			if(((s[sl].x >> bit) & 1) == 0){
    				lim = max(lim ,s[sl].l);
    			}
    			++sl;
    		}
    
    		if(ban[i]) dp[i] = 0;
    		else if(lim) dp[i] = (S[i - 1] - S[lim - 1] + MOD) % MOD;
    		else dp[i] = S[i - 1];
    		S[i] = (S[i - 1] + dp[i]) % MOD;
    	}
    	return dp[n + 1];
    }
    
    int main(){
    	n = read() ,k = read() ,m = read();
    	for(int i = 1 ; i <= m ; ++i){
    		s[i].l = read() ,s[i].r = read() ,s[i].x = read();
    	}
    	LL Ans = 1;
    	sort(s + 1 ,s + 1 + m);
    	for(int i = 0 ; i < k ; ++i){
    		Ans = Ans * solve(i) % MOD;
    	}
    	cout << Ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    [C语言
    [C语言
    [C语言
    [C语言
    [C语言
    [C语言
    [iOS]超详细Apache服务器的配置(10.10系统)
    IOS优秀博客
    「C」 数组、字符串、指针
    103.Binary Tree Zigzag Level Order Traversal(层序遍历)
  • 原文地址:https://www.cnblogs.com/imakf/p/13734282.html
Copyright © 2020-2023  润新知