天天看點

bupt_summer_train_dp優化

A - Sliding Window(poj 2823)

維護兩個單調隊列,一個遞增,一個遞減,并且保持在更新答案的時候,單調隊列的長度為k

關于這題,我實在忍不住吐槽了,加上輸入輸出挂時間快了10倍以上,簡直不能忍!

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
template <class T>
inline void write(T n)
{
    if(n < 0)
    {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n)
    {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
//--------------------------------------------- 

const int MAXN=1000010;

struct node
{
    int num;
    int i;
}q1[MAXN],q2[MAXN];

int maxn[MAXN],minn[MAXN];

int main()
{
    int n,k,i;
    while(read(n)&&read(k))
    {
        int top1,top2,tail1,tail2;
        top1=top2=tail1=tail2=0;
        int p;
        for(i=0;i<n;i++)
        {
            read(p);
            while(top1<tail1&&q1[tail1-1].num<p)
				tail1--;//遞減隊列
            q1[tail1].i=i,q1[tail1++].num=p;
            while(top2<tail2&&q2[tail2-1].num>p)
				tail2--;//遞增隊列
            q2[tail2].i=i,q2[tail2++].num=p;
            if(i>=k-1)
            {
				while(i-q1[top1].i>=k)
					top1++;
				while(i-q2[top2].i>=k)
					top2++;
				maxn[i-k+1]=q1[top1].num,minn[i-k+1]=q2[top2].num;	
            }
        }

        write(minn[0]);
        for(i=1;i<=n-k;i++)
        {
        	putchar(' ');write(minn[i]);
        }
        putchar('\n');
        write(maxn[0]);
        for(i=1;i<=n-k;i++)
        {
        	putchar(' ');write(maxn[i]);
        }
        putchar('\n');
    }
    return 0;
}
           

B -  Post Office (POJ1160)

a[i,j]表示在V[i..j]之間建立一個郵局的最小距離和,取中點維護

dp[i][j] = max{ dp[k][j-1] + ( min ( v[i] - v[t] , v[t] - v[k] ) , t=k+1...i-1 ) , k = j-1...i-1 }

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------

int v[305],a[305][305],p,n;
int dp[305][35];//代表在前x個村莊中建立y個郵局的最小的距離的


int main()
{

    read(n),read(p);
	for(int i=1;i<=n;i++)
		read(v[i]);
    for(int tmp=1;tmp<n;tmp++)
	{
        for(int i=0;i<=n-tmp;i++)
		{
			int j=i+tmp;
			a[i][j]=a[i+1][j]+v[(i+1+j)/2]-v[i];
		}
	}
	memset(dp,INF,sizeof(dp));
	for(int i=1;i<=n;i++)
		dp[i][1]=a[1][i];
	for(int i=2;i<=p;i++)
		for(int j=i;j<=n;j++)
			for(int k=i;k<=j;k++)
				if(dp[j][i]>dp[k][i-1]+a[k+1][j])
					dp[j][i]=dp[k][i-1]+a[k+1][j];

	printf("%d\n",dp[n][p]);
	return 0;
}
           

D - Print Article(HDU 3507)

dp[i] = min{ dp[j] + ( sum[i] - sum[j] ) ^ 2 +M }  0<j<i

斜率優化:

[ ( dp[j] + sum[j] * sum[j] ) - ( dp[k] + sum[k] * sum[k] ) ]  /  2 * ( sum[j] - sum[k] ) <= sum[i].

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}

template <class T>
inline void write(T n)
{
    if(n < 0)
    {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n)
    {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
//-----------------------------------

const int MAXN=500010;

ll c[MAXN],dp[MAXN]; 
ll q[MAXN];
int n,m;

ll Dp(int i,int j)
{
    return dp[j]+m+(c[i]-c[j])*(c[i]-c[j]);
}

ll Up(int j,int k)
{
	return fabs(dp[j]+c[j]*c[j]-(dp[k]+c[k]*c[k]));
}

ll Do(int j,int k)
{
	return 2*fabs(c[j]-c[k]);
}

int main()
{
	while(read(n)&&read(m))
	{
		
		for(int i=1;i<=n;i++)
		{
			read(c[i]);
			c[i]+=c[i-1];
		}
		dp[0]=0;
		int head=0,tail=0;
		q[tail++]=0;
		for(int i=1;i<=n;i++)
		{
			while(tail>head+1 && Up(q[head],q[head+1])<=c[i]*Do(q[head],q[head+1]))
				head++;
			dp[i]=Dp(i,q[head]);
			while(tail>head+1 && Up(i,q[tail-1])*Do(q[tail-1],q[tail-2])<=Up(q[tail-1],q[tail-2])*Do(i,q[tail-1]))
				tail--;
			q[tail++]=i;
		}
		printf("%lld\n",dp[n]);
	}
	return 0;
}
           

G - Picnic Cows(HDU 3045)

dp[i] = dp[j] + sum[i] - sum[j] - ( i - j )* a[j+1]

斜率優化:

dp[j] - sum[j] + j * a[j+1] - ( dp[i] - sum[i] + i * a[i+1] ) / a[j+1]-  a[i+1] <= i

并且維持 目标點與隊列尾 m 長度的大小

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
template <class T>
inline void write(T n)
{
    if(n < 0)
    {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n)
    {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
//-----------------------------------

const int MAXN=400010;
//dp[i] = dp[j] + sum[i] - sum[j] -(i - j)*a[j+1]


ll dp[MAXN],sum[MAXN],a[MAXN];
int q[MAXN];

ll getdp(int i,int j)
{
    return dp[j]+sum[i]-sum[j]-(i-j)*a[j+1];
}

ll getup(int j,int i)
{
    return dp[j]-sum[j]+j*a[j+1]-(dp[i]-sum[i]+i*a[i+1]);
}

ll getdown(int j,int i)
{
    return a[j+1]-a[i+1];
}

int main()
{
    int t,n;
    while(read(n)&&read(t))
    {
        for(int i=1;i<=n;i++)
            read(a[i]);
        sort(a+1,a+n+1);
        sum[0]=0;
        for(int i=1;i<=n;i++)
            sum[i]=sum[i-1]+a[i];
        int head=0,tail=0;
        dp[0]=0;
        q[tail++]=0;
        for(int i=t;i<=n;i++)
        {
            while(tail>head+1 && getup(q[head+1],q[head])<=i*getdown(q[head+1],q[head]))
                head++;
            dp[i]=getdp(i,q[head]);
            if(i>=2*t-1)
            {
                int j=i-t+1;
                while(tail>head+1 && getup(q[tail-1],q[tail-2])*getdown(j,q[tail-1])>=
                    getup(j,q[tail-1])*getdown(q[tail-1],q[tail-2]))
                        tail--;
                q[tail++]=j;
            }
        }
        write(dp[n]);putchar('\n');
    }
    return 0;
}
           

J - Trade

dp[i][j ]= max { dp[i-1][j] , dp[i-w-1][k] - ( j - k ) * ap[i] , dp[i-w-1][k] + ( k - j ) * bp[i] }

         i  表示天數    j表示股票數 

天數超過則 w 的限制則出隊

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#define eps 1e-9
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-----------------

struct Node
{
	int ap,bp;  //price
	int as,bs;	//num
}a[2010];

struct Que
{
	int v,i;
}q[2010];

int n,maxp,w;
int dp[2020][2020]; 

//dp[i][j]=max{dp[i-1][j],dp[i-w-1][k]-(j-k)*ap[i],dp[i-w-1][k]+(k-j)*bp[i]}
//         i  表示天數    j表示股票數 
//天數超過則推出 

int main()
{
	int T;
	read(T);
	while(T--)
	{
		read(n),read(maxp),read(w);
		memset(dp,0xcf,sizeof(dp));
		for(int i=1;i<=n;i++)
		{
			read(a[i].ap);read(a[i].bp);read(a[i].as);read(a[i].bs);
		}
		for(int i=1;i<=n;i++)  
	        for(int j=0;j<=min(a[i].as,maxp);j++)  
	            dp[i][j]=-a[i].ap*j;
  		for(int i=2;i<=n;i++)
  			for(int j=0;j<=maxp;j++)
  				dp[i][j]=max(dp[i][j],dp[i-1][j]);
  		for(int i=w+2;i<=n;i++)
  		{
			int pre=i-w-1;  	
			int head=0,tail=-1;
			for(int j=0;j<=maxp;j++)
			{
				dp[i][j]=max(dp[i-1][j],dp[i][j]);  
	            Que temp;  
	            temp.v=dp[pre][j]+j*a[i].ap;temp.i=j;
	            while(tail>=head&&temp.v>q[tail].v)	tail--;
	            q[++tail]=temp;
	            while(tail>=head&&fabs(j-q[head].i)>a[i].as)	head++;
	            if(tail>=head)
            		dp[i][j]=max(dp[i][j],q[head].v-j*a[i].ap);
			}	
			head=0,tail=-1;
			for(int j=maxp;j>=0;j--)
			{
				dp[i][j]=max(dp[i-1][j],dp[i][j]);  
	            Que temp;  
	            temp.v=dp[pre][j]+j*a[i].bp;temp.i=j;
	            while(tail>=head&&temp.v>q[tail].v)	tail--;
	            q[++tail]=temp;
	            while(tail>=head&&fabs(j-q[head].i)>a[i].bs)	head++;
	            if(tail>=head)
            		dp[i][j]=max(dp[i][j],q[head].v-j*a[i].bp);
			}
  		}
  		printf("%d\n",dp[n][0]);  
	}
	return 0;
}