更好体验
线段的贡献不好统计,考虑统计每一个点在不同情况中的被覆盖次数,那么每个点的被覆盖次数总和即为答案。
设 \(f_{i,j,0/1}\) 表示 \(i\) 点在扫描到线段 \(j\) 时是否被覆盖的情况数量,朴素的转移是暴力枚举每一条线段,方程如下。
当线段 \(j\) 可覆盖点 \(i\) 时
\[f_{i,j,0}=f_{i,j-1,0}+f_{i,j-1,1} \]\[f_{i,j,1}=2\times f_{i,j-1,0}+2\times f_{i,j-1,1} \]第一条柿子中,如果 \(i\) 尚未被覆盖,那么必须使用且运算,如果已被覆盖,那么就必须用取反。第二条柿子同理,当 \(i\) 尚未被覆盖,那么可以用或和取反,如果被覆盖,则可以用且和或。
当线段不覆盖 \(i\) 时
\[f_{i,j,0}=3\times f_{i,j-1,0}+f_{i,j-1,1} \]\[f_{i,j,1}=2\times f_{i,j-1,1} \]在第一个柿子中,如果 \(i\) 尚未覆盖,三种运算都合法,如果被覆盖就必须且运算。在第二个柿子中只能从已覆盖中转移而来,此时可以用或和取反。
此时留意到这个柿子转移方式一定,符合动态 dp 的形式,考虑用动态 dp 维护。去掉第二维,可将 dp 方程改写为矩阵形式。
\[\begin{bmatrix} f_{i,0}&f_{i,1}\end{bmatrix} =\begin{bmatrix} f_{i-1,0}&f_{i-1,1}\end{bmatrix} \times \begin{bmatrix}1&2\\1&2\\\end{bmatrix} \]\[\begin{bmatrix} f_{i,0}&f_{i,1}\end{bmatrix} =\begin{bmatrix} f_{i-1,0}&f_{i-1,1}\end{bmatrix} \times \begin{bmatrix}3&0\\1&2\\\end{bmatrix} \]其中第一个是点被覆盖,第二个是点不被覆盖,
用一个类似差分的方式记录线段的覆盖情况,在端点处修改对应线段的矩阵即可,具体可看代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
typedef long long ll;
using namespace std;
const ll mod=998244353,N=3e5+100;
vector<ll>inc[N],decd[N];
ll n,m,nn,ans,t1,t2;
struct matrix{
ll a[3][3];
void clear(){memset(a,0,sizeof(a));}
void one(){
for(ll i=1;i<=2;i++){
for(ll j=1;j<=2;j++){
if(i==j)a[i][j]=1;
else a[i][j]=0;
}
}
}
matrix operator *(const matrix&tmp )const{
matrix c;
c.clear();
for(ll i=1;i<=2;i++)
for(ll j=1;j<=2;j++)
for(ll k=1;k<=2;k++)
(c.a[i][j]+=a[i][k]*tmp.a[k][j]%mod)%=mod;
return c;
}
}D,ini;
struct EX_segment_tree{
matrix f[N<<2];
void modify(ll l,ll r,ll o,const ll &x,const matrix &d){
if(l==r)f[o]=d;
else {
ll mid=(l+r)>>1;
if(mid>=x)modify(l,mid,o<<1,x,d);
else modify(mid+1,r,o<<1|1,x,d);
f[o]=f[o<<1]*f[o<<1|1];
}
}
}T;
void non(){
D.a[1][1]=3,D.a[1][2]=0;
D.a[2][1]=1,D.a[2][2]=2;
}
void yeh(){
D.a[1][1]=1,D.a[1][2]=2;
D.a[2][1]=1,D.a[2][2]=2;
}
int main(){
cin>>n;
for(ll i=1;i<=n;i++){
ll a1,a2;
scanf("%lld%lld",&a1,&a2);
if(i==1)t1=a1,t2=a2;
else {
inc[a1].push_back(i-1);
decd[a2+1].push_back(i-1);
}
nn=max(nn,a2);
}
non();
for(ll i=1;i<n;i++)T.modify(1,n-1,1,i,D);
for(ll i=0;i<=nn;i++){
ini.clear();
if(i>=t1&&i<=t2)ini.a[1][2]=1;
else ini.a[1][1]=1;
yeh();
for(ll j=0;j<inc[i].size();j++){
ll x=inc[i][j];
T.modify(1,n-1,1,x,D);
}
non();
for(ll j=0;j<decd[i].size();j++){
ll x=decd[i][j];
T.modify(1,n-1,1,x,D);
}
ini=ini*T.f[1];
(ans+=ini.a[1][2])%=mod;
}
cout<<ans;
}
标签:end,覆盖,Union,题解,线段,times,bmatrix,Intersection,ll
From: https://www.cnblogs.com/caijiLYC/p/16890460.html