[6-7]考试总结

来源:互联网 发布:iphone4 ios7.1.2优化 编辑:程序博客网 时间:2024/05/20 06:23

年度最佳牛农

给你一个字符串,每次从串首或串尾拿出一个到一个新字符串的队尾,求字典序最小的串。
若队首队尾不一样直接贪心,否则你枚举队首还是队尾,看看谁更优即可。

手风琴与班卓琴

约翰的2N(3<=N<=1000)只奶牛正打算举办一场音乐会来吸收资金。其中,N只奶牛是手风琴手,而另N只奶牛是班卓琴手。每个手风琴手有一个天才指数Ai(0<=Ai<=1000),同样一个班卓琴手有一个天才指数Bi(0<=Bi<=1000)。
约翰打算给手风琴手和班卓琴手配对。如果让手风琴手i与班卓琴手j配对,她们吸收的资金将是Ai * Bj。所以约翰可以用他的聪明才智选择一种最好的搭配方式,让奶牛们吸收的总资金最大化。
不幸的是,约翰的手风琴手有一个怪癖:如果手风琴手i已经和班卓琴手j配对,那手风琴手i+1到N,绝不肯与班卓琴手1到j-1间的某一个配对。这让约翰的搭配计划造成了很多不便。而且,约翰也意识到,适当地让一些奶牛放弃配对,不要参加音乐会,会让吸收的总资金更大。
然而,那些失去机会的失落奶牛,为了消解她们的孤独与痛苦,正成群结队地到就把去喝冰镇橙味酒。如果从x号到y号手风琴手均是失落的奶牛(x-1号和y+1号奶牛不存在或参加了演出),这y-x+1只奶牛会结成一伙去喝酒,而且她们的消费量是
同样,对于班卓琴手也有这样的规律。
面对未来可能产生的巨额酒费支出,约翰不得不再认真考虑他的配对计划了。请你帮忙计算最大的收益是多少?
先有一个四方的dp,然后发现dp[i][j]只能从dp[i-1][j1]或dp[i1][j-1]转移,因为如果有空的话可以再差一个。然后就是玩具装箱般的斜率优化。
太工业了,必须贴代码。

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<map>#include<queue>#include<vector>#include<cassert>#include<ctime>#include<climits>#define X first#define Y second#define MP make_pair#define pii pair<int,int>#define LL long long#define DB double#define INF LONG_LONG_MAX/1000#define pb push_back#define sqr(_) ((_)*(_))#define DEBUG(...) fprintf(stderr,__VA_ARGS__)using namespace std;template<class T> void Read(T& x){    x=0;int flag=0,sgn=1;char c;    while(c=getchar())    {        if(c=='-')sgn=-1;        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;        else if(flag)break;    }    x*=sgn;}#define int LLconst int MAXN=2001;int A[MAXN],B[MAXN],dp[MAXN][MAXN],n,s[2][MAXN];int q[MAXN],first,last;int ans=-INF;struct Queue1{    int q[MAXN],first,last;     Queue1(){        first=last=0;        q[last++]=1;    }    DB slope(int id,int x,int y)    {        if(s[1][y]==s[1][x])        {            DB k=dp[id][x]-dp[id][y]-sqr(s[1][x])+sqr(s[1][y]);            if(k==0)return 0;            return k>0?INF:-INF;        }        return (DB)(dp[id][x]-dp[id][y]-sqr(s[1][x])+sqr(s[1][y]))/(DB)(s[1][y]-s[1][x]);    }    void insert(int id,int i)    {        while(first<last-1&&(DB)slope(id,q[last-2],q[last-1])>=(DB)slope(id,q[last-1],i))            last--;        q[last++]=i;    }    void work(int id,int i,int j)    {        while(first<last-1&&(DB)slope(id,q[first],q[first+1])<=(DB)2*s[1][j-1])            first++;        dp[i][j]=max(dp[i][j],dp[id][q[first]]-sqr(s[1][j-1]-s[1][q[first]])+A[i]*B[j]);        ans=max(ans,dp[i][j]-sqr(s[0][n]-s[0][i])-sqr(s[1][n]-s[1][j]));    }}q1[MAXN];struct Queue2{    int q[MAXN],first,last;    Queue2(){        first=last=0;        q[last++]=1;    }    DB slope(int id,int x,int y)    {        if(s[0][x]==s[0][y])        {            DB k=dp[x][id]-dp[y][id]-sqr(s[0][x])+sqr(s[0][y])>=0;            if(k==0)return 0;            return k>0?INF:-INF;        }        return (DB)(dp[x][id]-dp[y][id]-sqr(s[0][x])+sqr(s[0][y]))/(DB)(s[0][y]-s[0][x]);    }    void insert(int id,int i)    {        while(first<last-1&&(DB)slope(id,q[last-2],q[last-1])>=(DB)slope(id,q[last-1],i))            last--;        q[last++]=i;    }    void work(int id,int i,int j)    {        while(first<last-1&&(DB)slope(id,q[first],q[first+1])<=(DB)2*s[0][i-1])            first++;        dp[i][j]=max(dp[i][j],dp[q[first]][id]-sqr(s[0][i-1]-s[0][q[first]])+A[i]*B[j]);        ans=max(ans,dp[i][j]-sqr(s[0][n]-s[0][i])-sqr(s[1][n]-s[1][j]));    }}q2[MAXN];main(){    Read(n);    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++)s[0][i]=s[0][i-1]+A[i],s[1][i]=s[1][i-1]+B[i];    for(int i=0;i<MAXN;i++)        for(int j=0;j<MAXN;j++)            dp[i][j]=-INF;    dp[0][0]=0;    s[1][n+1]=s[1][n];    s[0][n+1]=s[0][n];    for(int i=1;i<=n;i++)    {        dp[1][i]=A[1]*B[i]-sqr(s[1][i-1]);        ans=max(ans,dp[1][i]-sqr(s[0][n]-s[0][1])-sqr(s[1][n]-s[1][i]));        dp[i][1]=A[i]*B[1]-sqr(s[0][i-1]);        ans=max(ans,dp[i][1]-sqr(s[0][n]-s[0][i])-sqr(s[1][n]-s[1][1]));    for(int i=2;i<=n;i++)        for(int j=1;j<=n;j++)        {               if(j!=1)q1[i-1].work(i-1,i,j);            if(j!=1)q2[j-1].work(j-1,i,j);            q1[i-1].insert(i-1,j);            q2[j].insert(j,i-1);        }    cout<<ans<<endl;}

数列

给定一个长度为N的数列{an},你需要按照将这个数列分割成若干个子段,要求每一段的累加和不能超过给定的M,并且你需要求出每一段最大值的累加和,显然你必须保证累加和越小越好。
设dp[i]为答案,dp[i]=min(dp[j]+max(j+1,i)。
我们用线段树转移,每个节点维护区间内最小的dp值和最小的dp[j]+max(j+1,i)值。
预处理出每个数往左以它为最大值最多到哪里l[i]。
每扫到一个数,在线段树里面区间改即可。

总结

以为还剩30min的时候以为第三题不太好做,其实好傻逼啊,当时颓废的心已经起来了,不想想题了。。。还有就是第二题肛太久,没有发现三方的dp,何谈斜率优化。第一题如果想了超过70min赶紧弃疗,第二三题谁简单就一直肛谁。

0 0
原创粉丝点击