# Codeforces 1327F AND Segments > https://codeforces.com/contest/1327/problem/F 題意為有長度$n$之序列$a$,其中$1 \le a_i \lt 2^k$,給$m$個條件$(l_i, r_i, x_i)$,表示在子陣列$[a_{l_i}, a_{r_i}]$ 裡全部的數AND後必須為$x_i$,求總共有多少個$a$滿足條件。$1 \le n \le 5 \times 10^5$,$1 \le k \le 30$,$0 \le m \le 5 \times 10^5$。 這題裡面有一個子問題困擾了我很久,筆記一下。 給條件index區間$[l, r]$裡全部的數AND後要等於$x$,於是很直覺的拆成每個bit來想,如果第$k$個bit等於$1$,那表示區間中的數在第$k$個bit都要是$1$;反之如果第$k$個bit等於$0$,那表示區間中的數在第$k$個bit至少有一個$0$。 於是問題分解成獨立的對於每個bit,有$m$個區間限制,第一類為限制都是$1$,第二類則是區間中至少要有一個$0$,答案為每個bit貢獻的乘積,這可以用DP來解決。 定義$dp(i)$為將第$i$個index放$0$且小於$i$的index都符合條件的方案總數(不考慮$i$之後的情況),於是考慮怎麼轉移,對於第一類包括$i$之區間$dp(i)=0$,對於第二類區間想一下在$i$為$0$時必須由$\lt i$的哪邊轉移過來,對於已經包含$i$的區間已經可以隨便放,沒條件的也可隨便放,都可以轉移過來,於是考慮不包刮$i$的第二類區間,則轉移方程為: \begin{array}{ll} dp(i) = \sum_{k=最靠近i且不包含i的最靠近i的左區間}^{i-1} dp(k)。 \end{array} 最靠近$i$且不包含$i$的最靠近$i$的左區間怎麼快速計算讓我想了很久==(感覺用multiset就過不了),於是我就爛,看了別人的code學了一些技巧,定義$L(i)$為在所有第二類右區間$\le i$的區間中最靠近的左區間,這樣的話$dp(i)$求和下界就是$L(i-1)$。最後算到$dp(n+1)$就是對於該bit的總數了。 ```cpp= #include <bits/stdc++.h> #pragma GCC optimize(3) #define ll long long #define pii pair<int, int> #define pll pair<long long, long long> #define F first #define S second #define endl '\n' using namespace std; const int inf = 0x3f3f3f3f; const ll Inf = 1e18; const int mod = 998244353; const int N = 5e5 + 5; int n, k, m; int l[N], r[N], x[N], L[N], one[N]; ll dp[N], pre[N]; void solve(){ cin >> n >> k >> m; for(int i=1; i<=m; i++){ cin >> l[i] >> r[i] >> x[i]; } auto cal = [&](int kk){ for(int i=0; i<=n+1; i++) dp[i] = pre[i] = L[i] = one[i] = 0; for(int i=1; i<=m; i++){ if((x[i]>>kk) & 1){ one[l[i]]++; one[r[i]+1]--; } else{ L[r[i]] = max(L[r[i]], l[i]); } } for(int i=1; i<=n+1; i++){ one[i] += one[i-1]; L[i] = max(L[i-1], L[i]); } dp[0] = pre[0] = 1; for(int i=1; i<=n+1; i++){ if(!one[i]){ dp[i] = pre[i-1]; if(L[i-1] > 0) dp[i] = (dp[i] - pre[L[i-1] - 1] + mod) % mod; } pre[i] = (dp[i] + pre[i-1]) % mod; } return dp[n+1]; }; ll ans = 1; for(int i=0; i<k; i++){ ans = (ans * cal(i)) % mod; if(!ans) break; } cout << ans << endl; } int main(){ ios::sync_with_stdio(0); cin.tie(0); //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int t = 1; // cin >> t; while(t--) solve(); return 0; } ``` ### 時間複雜度 :$O(nk)$ ###### tags: `dp`