CF1327F AND Segments

传送门
1.位运算相关,看每一位是否独立。此题中每一位独立,所以可以对每一位单独算方案数最后相乘
2.DP状态设计,预处理及空间时间复杂度优化。首先设\(dp_{i,j}\)表示填好\(1\)~\(i\)位时,最后一个\(0\)\(j\)位置的方案数,此时若想要转移,需要考虑对于当前第\(i\)位,最后一个\(0\)在什么位置的时候是不符合题意的,于是需要预处理出一个\(pos_i\)表示对于\(i\)位置以前,最后一个\(0\)至少应该出现的位置。于是对于
\(j < pos_i\)\(dp_{i,j}=0\)
\(pos_i≤j<i\)\(dp_{i,j}=dp_{i-1,j}\),因为最后一个\(0\)\(j\)的话说明后面都填\(1\)
\(j=i\),则当前位填\(0\),前面填什么都行,故\(dp_{i,i}= \sum_{1}^{i-1} dp_{i-1,j}\)
注意到此时\(i\)只与\(i-1\)有关,故可以将第一维省略,这样空间复杂度解决。至于时间复杂度,我们发现可以维护一个前缀和来更新,故时间复杂度也解决。
需要注意最后统计答案应该用\(dp_{n+1}\),因为如果仅仅是\(dp_n\)表示的是最后一位填\(0\),而最后一位填\(1\)的情况会漏掉

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

using namespace std;

const int N = 5e5 + 10;
const int inf = 1e18 + 10;
const int mod = 998244353;
int n,k,m,ans = 1;
struct node {
    int l,r,x;
}in[N];

void solve() {
    cin >> n >> k >> m;
    for(int i = 1;i <= m;i++)
        cin >> in[i].l >> in[i].r >> in[i].x;
    for(int i = 0;i < k;i++) {
        vector<int> pos(n + 10),dp(n + 10),d(n + 10);
        for(int j = 1;j <= m;j++) 
            if(in[j].x >> i & 1) {
                d[in[j].l]++;d[in[j].r + 1]--;
            }
            else pos[in[j].r + 1] = max(pos[in[j].r + 1],in[j].l);
        for(int j = 1;j <= n + 1;j++) {
            d[j] += d[j - 1];
            pos[j] = max(pos[j],pos[j - 1]);
        }
        dp[0] = 1;
        int sum = 1,l = 0;
        for(int j = 1;j <= n + 1;j++) {
            while(l < pos[j]) {
                sum = (sum - dp[l] + mod) % mod;
                dp[l] = 0;
                l++;
            }
            dp[j] = d[j] ? 0 : sum;
            sum = (sum + dp[j]) % mod;
        }
        ans = ans * dp[n + 1] % mod;
    }
    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-08-13 13:06  孤枕  阅读(7)  评论(0)    收藏  举报