一、题目
二、解法
对于这类二进制问题,由于每一位是独立的,我们可以把每一位分开来看,这道题就是求出每一位的方案数最后求乘积即可。
现在问题就变成了一段区间全为
1
1
1或者一段区间不全为
1
1
1,定义
d
p
[
i
]
dp[i]
dp[i]为第
i
i
i位选
0
0
0,前面全合法的方案数,答案是
d
p
[
n
+
1
]
dp[n+1]
dp[n+1],如果这一位钦定选
1
1
1那么
d
p
[
i
]
=
0
dp[i]=0
dp[i]=0,转移就是找到一个右端点比
i
i
i小,左端点(记为
l
l
l)最大的不全选
1
1
1的区间,必须在这其中选
0
0
0:
d
p
[
i
]
=
∑
j
=
l
i
−
1
d
p
[
j
]
dp[i]=\sum_{j=l}^{i-1}dp[j]
dp[i]=j=l∑i−1dp[j]那么我们维护一个前缀和,维护一个这样的左端点,就可以做了,时间复杂度
O
(
30
n
)
O(30n)
O(30n)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 500005;
const int MOD = 998244353;
#define int long long
int read()
{
int num=0,flag=1;
char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
return num*flag;
}
int n,m,k,ans,l[M],r[M],x[M],dp[M],p[M],s[M];
signed main()
{
n=read();k=read();m=read();ans=1;
for(int i=1;i<=m;i++)
{
l[i]=read();r[i]=read();x[i]=read();
}
for(int i=0;i<k;i++)
{
for(int j=0;j<=n+1;j++)
dp[j]=p[j]=s[j]=0;
for(int j=1;j<=m;j++)
if(x[j]&(1<<i))
dp[l[j]]-=1,dp[r[j]+1]+=1;
else
p[r[j]]=max(p[r[j]],l[j]);
for(int j=1;j<=n+1;j++)
dp[j]+=dp[j-1];
dp[0]=s[0]=1;
int ml=0;
for(int j=1;j<=n+1;j++)
{
if(dp[j]<0) dp[j]=0;
else dp[j]=s[j-1]-(ml==0?0:s[ml-1]);
ml=max(ml,p[j]);
s[j]=(s[j-1]+dp[j])%MOD;
}
ans=ans*dp[n+1]%MOD;
}
printf("%lld\n",(ans+MOD)%MOD);
}