CF573D Bear and Cavalry

原题链接

比较简单的 dp 题。

看见题目的 wihi 式子,很容易想到排序不等式,所以我们先对 w,h 排序,然后分情况讨论。

  • wi,hi 对应的编号不相等,肯定是把它们配对。

  • wi,hi 对应的编号相等,考虑这样的连法:

  • 若是这种情况也不合法,或者它们之后又有一个点不合法,我们再加一个点,会得到两种情况:

而这样一定可以得到最优,之后不合法的规模继续扩大,我们也可以拆分成上述的小问题。

所以转移方程易得:fi=max{fi1+wihifi2+wihi1+wi1hifi3+wihi1+wi1hi2+wi2hifi3+wihi2+wi1hi+wi2hi1

从大往小进行转移,转移前注意判断是否合法,时间复杂度 O(nq),卡卡常似乎能过。

但是这个方程明显支持矩阵优化,我们列出转移矩阵,用线段树维护即可。

我们用广义矩阵乘法:Ci,j=maxk=1mAi,k+Bk,j,然后列出式子:

[fi1fi2fi3]×[wihiwihi1+wi1himax{}0INFINFINF0INF]=[fifi1fi2]

注意线段树 pushup 时的顺序,我们的转移是从大往小做的。

#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define ll long long
#define in inline
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x*f;
}
const int N=1e5+10;
const ll INF=1e17;
int n,q,w[N],h[N],idw[N],idh[N],dw[N],dh[N],tmp[N];
bool cmp(int a,int b){return tmp[a]<tmp[b];}
struct matrix{
	ll a[3][3];
	matrix(){memset(a,0,sizeof(a));}
	matrix operator*(matrix const&T){
		matrix res;
		FOR(i,0,2) FOR(j,0,2) res.a[i][j]=-INF;
		FOR(i,0,2){
			FOR(k,0,2){
				ll r=a[i][k];
				FOR(j,0,2) res.a[i][j]=max(res.a[i][j],r+T.a[k][j]);
			}
		}
		return res;
	}
}g[N],tr[N<<2];
void pushup(int u){tr[u]=tr[u<<1|1]*tr[u<<1];}
void build(int u,int l,int r){
	if(l==r){tr[u]=g[l];return;}
	int mid=(l+r)>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	pushup(u);
}
void modify(int u,int l,int r,int x){
	if(l==r){tr[u]=g[l];return;}
	int mid=(l+r)>>1;
	if(x<=mid) modify(u<<1,l,mid,x);
	else modify(u<<1|1,mid+1,r,x);
	pushup(u);
}
void init(int x){
	if(idw[x]!=idh[x]) g[x].a[0][0]=1ll*w[x]*h[x];
	else g[x].a[0][0]=-INF;
	if(x>1) g[x].a[0][1]=(idw[x]!=idh[x-1]&&idw[x-1]!=idh[x])?1ll*w[x]*h[x-1]+1ll*w[x-1]*h[x]:-INF;
	else g[x].a[0][1]=-INF;
	if(x>2){
		bool flag=false;ll res=-INF;
		if(idw[x]!=idh[x-1]&&idw[x-1]!=idh[x-2]&&idw[x-2]!=idh[x])
			flag=true,res=max(res,1ll*w[x]*h[x-1]+1ll*w[x-1]*h[x-2]+1ll*w[x-2]*h[x]);
		if(idw[x]!=idh[x-2]&&idw[x-1]!=idh[x]&&idw[x-2]!=idh[x-1])
			flag=true,res=max(res,1ll*w[x]*h[x-2]+1ll*w[x-1]*h[x]+1ll*w[x-2]*h[x-1]);
		g[x].a[0][2]=res;
	}
	else g[x].a[0][2]=-INF;
	g[x].a[1][0]=g[x].a[2][1]=0,g[x].a[1][1]=g[x].a[1][2]=g[x].a[2][0]=g[x].a[2][2]=-INF;
}
int main(){
	n=rd,q=rd;
	FOR(i,1,n) w[i]=rd,idw[i]=i,tmp[i]=w[i];
	sort(idw+1,idw+1+n,cmp);
	FOR(i,1,n) w[i]=tmp[idw[i]];
	FOR(i,1,n) h[i]=rd,idh[i]=i,tmp[i]=h[i];
	sort(idh+1,idh+1+n,cmp);
	FOR(i,1,n) h[i]=tmp[idh[i]];
	FOR(i,1,n) dw[idw[i]]=i,dh[idh[i]]=i;
	FOR(i,1,n) init(i);
	build(1,1,n);
	while(q--){
		int x=rd,y=rd;
		swap(dh[x],dh[y]),swap(idh[dh[x]],idh[dh[y]]);
		FOR(i,dh[x],min(n,dh[x]+2)) init(i),modify(1,1,n,i);
		FOR(i,dh[y],min(n,dh[y]+2)) init(i),modify(1,1,n,i);
		printf("%lld\n",tr[1].a[0][0]);
	}
	return 0;
}
posted @   summ1t  阅读(7)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示