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;
}

浙公网安备 33010602011771号