CF1743F Intersection and Union 题解

更好体验
线段的贡献不好统计,考虑统计每一个点在不同情况中的被覆盖次数,那么每个点的被覆盖次数总和即为答案。
\(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;
}
posted @ 2022-11-14 21:17  蒟蒻丁  阅读(23)  评论(0编辑  收藏  举报