「AGC040E」Prefix Suffix Addition 题解 (DP)

题目简介

你有一个长为 N 的序列 x1,x2,,xN,一开始全部为 0,你现在可以以任意顺序进行任意次以下两种操作:

  1. 选定整数 k(1kN)不下降非负序列 c1,c2,,ck,对所有 1ik,令 xi 加上 ci
  2. 选定整数 k(1kN)不上升非负序列 c1,c2,,ck,对所有 1ik,令 xNk+i 加上 ci

问最少进行多少次操作使得最后对任意 ixi=Ai

转化

0x1.

由于 x 的初始值全为 0 ,所以可以考虑将其翻一转,变成

  1. 选定整数 k(1kN)不上升非负序列 c1,c2,,ck,对所有 1ik,令 xi 加上 ci
  2. 选定整数 k(1kN)不下降非负序列 c1,c2,,ck,对所有 1ik,令 xNk+i 加上 ci

这样,对于操作1,可视为 ck+1cN=0

对于操作2,可将cNk+1cN赋值为c1ck,然后令c1ck=0

操作1的所有序列叠加,所得的还是不上升非负序列,记为 B

操作2的所有序列叠加,所得的还是不下降非负序列,记为 C

可得 Ai=Bi+Ci,转换得 Ci=AiBiA已知,DP求 B 即可。

0x2.

fi,j 表示 DP 到第 i 个位置,其中 Bi=j 的最小值。

由:

fi,Bi=minfi1,Bi1+[Bi<Bi1]+[Ci>Ci1]

不难得出状态转移方程:

fi,j=minfi1,k+[j<k]+[Aij>Ai1k]

变形:

fi,j=minfi1,k+[j<k]+[j<kAi1+Ai]

0x3.

由上式可知,j 越大,越难满足 j<kj<kAi1+Ai

也就是说,k 越小,越容易满足 j<kj<kAi1+Ai

另外,对于已知状态fi1,kfi,j 只可能有三种值

  • fi1,k
  • fi1,k+1
  • fi1,k+2

换句话说,如果对于 fi,j ,有 fi,j<fi,j2,那么 fi,j 是无意义的。

0x4

偷换概念

使用 fi,j 表示,当DP到前 i 位,最小值为 j 时对应的 Bi 最小值。

即 将原本的fi,j概念调换一下。

使用map进行DP。

AC Code

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<functional>
int main(){
	int n;std::cin>>n;
	std::vector<int>a(n+1);
	std::map<int,int>f[2];
	int cur=0;
	for(int i=1;i<=n;++i)std::cin>>a[i];
	std::function<void(int,int,int)>update=
	[&](int k,int x,int y){
		if(!f[k].count(x))f[k][x]=y;
		f[k][x]=std::min(f[k][x],y);
	};
	f[cur][0]=a[1],f[cur][1]=0;
	for(int i=2;i<=n;++i){
		cur^=1;f[cur].clear();
		int v1=std::max(a[i]-a[i-1],0);
		int v2=std::min(a[i]-a[i-1],0);
		for(auto it=f[cur^1].begin();it!=f[cur^1].end();++it){
			if(it->first-f[cur^1].begin()->first>2)continue;
			int x=it->first;
			int y=it->second;
			if(v1+y<=a[i])update(cur,x,std::max(v1+y,0));
			if(v2+y<=a[i])update(cur,x+1,std::max(v2+y,0));
			if(v2+y>0)update(cur,x+2,0);
		}
	}
	int ans=n;
	for(auto it=f[cur].begin();it!=f[cur].end();++it)
		ans=std::min(ans,it->first+(it->second>0));
	std::cout<<ans<<'\n';
	return 0;
}

EOF

posted @   AlienCollapsar  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq
点击右上角即可分享
微信分享提示