[ZJOI2020] 序列 线性规划做法/贪心做法

线性规划做法

同时也作为线性规划对偶的一个小小的学习笔记。

以下 表示点积,b,c,x,y 是行向量。

A 是矩阵,对于向量 u,vi,uivi 则称 uv 同理。

线性规划标准型:

maxcxs.t.{Axbx0

它的对偶是:

minbys.t.{ATycy0

弱对偶定理:maxcxminby

我们可以任意取可行域中的 x,y,然后对于 yTAx 一方面由于 yT 非负有 yTAxyTb=by,另一方面 yTAx=(yAT)TxcTx=cx,即得证。

强对偶定理:maxcx=minby。也就是说我们可以把线性规划转为其对偶问题进行求解。

回到这道题,给每一个区间的每一种操作编号 1M,对于第 t 个操作设其下标集合为 It,我们建一个变量 xt,表示这个操作重复做的次数。我们放宽 xtR,可以证明最优解仍然是整数。

将取等条件拆成两个条件,那么答案是:

mint=1Mxts.t.{t=1M[iIt]xtait=1M[iIt]xtaixt0

对偶一下,有:

maxi=1nai(piqi)s.t.{i=1n[iIt](piqi)1pi,qi0

容易发现 piqi 可以取任意实数,设 yi=piqi,有:

maxi=1naiyis.t.i=1n[iIt]yi1

这里 yhx 大佬的博客中讲此矩阵是全单模矩阵,也就是说线性规划可行域的顶点全是整数所以这个线性规划具有整数性?不太了解什么是全单模 QAQ。

既然有整数性,那么考虑拿着这个东西做。该线性规划的实际意义是让我们对每个位置赋权,使得每种操作下标的权值之和都 1

经典套路,类似最大子段和,记录三种操作后缀和的最大值 x,y,z 来 DP。由限制有 x,y,z1。而如果有 x/y/z<0,那么我们就需要”截断“然后新开一个后缀。同时这也说明了 yi 有意义的取值只有 0,1,1<1 的都是”截断“而总权值没有 1 优秀所以一定不会取。

时间复杂度 O(n)24 的常数。

#include <cstdio>
#include <algorithm>
#define forxyz \
for(int x=0;x<2;++x) \
for(int y=0;y<2;++y) \
for(int z=0;z<2;++z)
using namespace std;
int read(){
char c=getchar();int x=0;
while(c<48||c>57) c=getchar();
do x=(x<<1)+(x<<3)+(c^48),c=getchar();
while(c>=48&&c<=57);
return x;
}
typedef long long ll;
const int N=100003;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n;
int a[N];
ll f[N][2][2][2];
void solve(){
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) forxyz f[i][x][y][z]=-INF;
f[0][0][0][0]=0;
for(int i=1;i<=n;++i){
forxyz{
for(int d=-1;d<=1;++d){
if(x+d>1||y+d>1) continue;
ll &dp=f[i][max(x+d,0)][z][max(y+d,0)];
dp=max(dp,f[i-1][x][y][z]+d*a[i]);
}
}
}
ll res=0;
forxyz res=max(res,f[n][x][y][z]);
printf("%lld\n",res);
}
int main(){
int tc=read();
while(tc--) solve();
return 0;
}

贪心做法

解析咕了,具体看洛谷题解区。

#include <cstdio>
#include <algorithm>
using namespace std;
int read(){
char c=getchar();int x=0;
while(c<48||c>57) c=getchar();
do x=(x<<1)+(x<<3)+(c^48),c=getchar();
while(c>=48&&c<=57);
return x;
}
typedef long long ll;
void solve(){
int n=read();
ll a=0,b=0,c=0,res=0,las=read();
for(int i=2;i<=n+1;++i){
ll x=0;
if(i<=n) x=read();
ll dlt=0;
if(x<a+b){
dlt=a+b-x;
if(a<dlt) b-=dlt-a,dlt=a;
if(b<dlt) a-=dlt-b,dlt=b;
a-=dlt;b-=dlt;x-=dlt;
}
x-=a+b;
ll mn=min(las,x);
res+=mn;las-=mn;x-=mn;a+=mn;
res+=las;c+=las;
x+=dlt;res-=dlt;
las=x;
swap(b,c);
}
printf("%lld\n",res);
}
int main(){
int tc=read();
while(tc--) solve();
return 0;
}
posted @   yyyyxh  阅读(174)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示