JZOJ5259. 线性规划问题

来源:互联网 发布:淘宝人工客服电话 编辑:程序博客网 时间:2024/06/05 06:17

这里写图片描述
这里写图片描述

分析

非常容易就可以想到一个三维状态:fi,j,k
表示当前是序列的第i个位置,前面选的a的和是j,b的和是k的最小值。
转移很显然。

但是这只能得到50分。

我们考虑压缩一下状态,
fi,j
表示第i个位置,a的和≤j,b的和≥j的最小值。
这样状态就是二维的,
转移:
fi,j=jaik=jbiminfi1,k
这里是要求连续的一个区间中的最小值,
想到用单调队列。
每次将fi1,jai 进队,
判断对首的进队时间是否早于jbi
更新当前状态fi,j
上面是xi=1 的情况的转移,
xi=0 的情况转移就非常简单了,
就是fi,j=min(fi,j,fi1,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 23332333using 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[N],b[N],c[N],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');    }}
原创粉丝点击