JZOJ5259. 线性规划问题

JZOJ5259. 线性规划问题_第1张图片
JZOJ5259. 线性规划问题_第2张图片

分析

非常容易就可以想到一个三维状态: 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
#include
#include
#include 
#include 
#include 
#include 
#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[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]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');
    }
}

你可能感兴趣的:(题解,DP,单调队列)