题意:
需要你构造长度为n的序列,要求是,每个数的大小<
2
k
2^k
2k,并且有m个区间,每个区间
题解:
那么一般来说可以按位分解的题目是枚举每一位去做的,而且这道题每个位置上的数的每一位都是互不影响的,那么肯定是一位一位去考虑然后乘法原理乘起来。
然后根据题意我们可以知道每个区间,如果要求的数的第i位是1,那么这个区间里面所有的数的第i位一定是1,如果是0,那么这个区间里面所有数的第i位至少有一个数是0.
这道题的数据范围是5e5,之后我就没有再想二维的做法了,但是应该是二维的做法,最终由于这道题的特殊性质可以转换成一维的。
dp[i][j]表示到第i位的时候,最后一个0在第j位的时候的情况数。
状态转移方程就是,
dp[i][j]=dp[i-1][j](0<=j<i)
dp[i][i]=sum{0<=j<i|dp[i-1][j]}
此时可以发现第i位只和地i-1位有关,并且除了dp[i][i],其余的数都是和前面一样的。所以直接去掉第一维,用dp[j]表示即可,然后用sum维护前缀和。
然后的话用差分维护当前这一位是否需要1,如果需要,那么dp[i]=0,否则
dp[i]=sum,sum*=2
*2是因为dp[i-1]就是前缀和,然后再加一个前缀和就是两倍。
然后对于区间的约束,到了当前位置如果区间l-i是要求有一个0,那么需要减去l之前的dp值,因为不存在
d
p
[
i
]
[
j
]
(
0
<
=
j
<
l
)
dp[i][j](0<=j<l)
dp[i][j](0<=j<l)了
That’s all
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+5;
const ll mod=998244353;
ll dp[N];
vector<int>add[N],del[N];
int lef[N],l[N],r[N],v[N];
int main()
{
int n,k,m;
scanf("%d%d%d",&n,&k,&m);
ll ans=1;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&l[i],&r[i],&v[i]),add[l[i]].push_back(v[i]),del[r[i]+1].push_back(v[i]);
for(int bit=0;bit<k;bit++){
memset(lef,0,sizeof(lef));
for(int i=1;i<=m;i++)
if(!(v[i]&(1<<bit)))
lef[r[i]]=max(lef[r[i]],l[i]);
memset(dp,0,sizeof(dp));
int num=0,f=0,pos=0;
ll sum=dp[0]=1;
for(int i=1;i<=n;i++){
for(auto j:add[i])
num+=(j&(1<<bit))>0;
for(auto j:del[i])
num-=(j&(1<<bit))>0;
if(!num)
dp[i]=sum,sum=(sum*2)%mod;
while(pos<lef[i])
sum=(sum-dp[pos++]+mod)%mod;
}
ans=ans*sum%mod;
}
printf("%lld\n",ans);
return 0;
}