您的位置:首页 > 其它

JZOJ5259. 线性规划问题

2017-08-11 16:22 197 查看




分析

非常容易就可以想到一个三维状态:fi,j,k

表示当前是序列的第i个位置,前面选的a的和是j,b的和是k的最小值。

转移很显然。

但是这只能得到50分。

我们考虑压缩一下状态,

设fi,j

表示第i个位置,a的和≤j,b的和≥j的最小值。

这样状态就是二维的,

转移:

fi,j=∑j−aik=j−biminfi−1,k

这里是要求连续的一个区间中的最小值,

想到用单调队列。

每次将fi−1,j−ai 进队,

判断对首的进队时间是否早于j−bi

更新当前状态fi,j

上面是xi=1 的情况的转移,

xi=0 的情况转移就非常简单了,

就是fi,j=min(fi,j,fi−1,j)

code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 1003
#define db double
#define P putchar
#define G getchar
#define mo 23332333
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=G();
n*=w;
}
void write(int x)
{
if(x>9) write(x/10);
P(x%10+'0');
}
int f[2][N*10],w,a
,b
,c
,l,r,d[N*10],ti[N*10];
int T,n,p;
int main()
{
read(T);
while(T--)
{
read(n);read(p);
for(int i=1;i<=n;i++)
read(a[i]);
for(int i=1;i<=n;i++)
read(b[i]);
for(int i=1;i<=n;i++)
read(c[i]);

memset(f[w],127,sizeof(f[w]));f[w][0]=0;
for(int i=1;i<=n;i++)
{
w=1-w;
memcpy(f[w],f[1-w],sizeof(f[w]));
l=1;r=0;
for(int j=a[i];j<=p;j++)
{
/*for(int k=max(0,j-b[i]);k<=j-a[i];k++)
f[w][j]=min(f[w][j],f[1-w][k]+c[i]);*/
while(l<=r && d[r]>=f[1-w][j-a[i]])r--;
d[++r]=f[1-w][j-a[i]];ti[r]=j-a[i];
while(ti[l]<j-b[i])l++;
f[w][j]=min(f[w][j],d[l]+c[i]);
}
}
if(f[w][p]>1000000000)P('I'),P('M'),P('P'),P('O'),P('S'),P('S'),P('I'),P('B'),P('L'),P('E'),P('!'),P('!'),P('!');
else write(f[w][p]);
P('\n');
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息