地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最长的宽。土地的长和宽是不能交换的,例如一块2*5的土地和一块5*2的土地放在一起,价格为5*5=25。ZXR想知道最少花费多少钱可以买下所有的土地。
Input:
第一行一个数n表示一共有n块土地。
接下来n行每行两个数xi和yi分别表示每块土地的长和宽。
Output:
一行一个数表示最小价格
先sort一遍如果它的y值也比数组的y值小的化那么这个点对于更新答案没有作用就删去tot--
最后由dp[i]=dp[j]+x[i]*y[i+1]可以推出dp[j]-dp[k]<=x[i]*(y[k+1]-y[j+1])就可以进行斜率优化了
粘上代码
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn=50005; struct p { long long x,y; }node[maxn]; long long n,x[maxn],y[maxn],tot=0,dp[maxn],q[maxn]; bool cmp(p a,p b) { return a.x==b.x?a.y<b.y:a.x<b.x; } double xielv(int k,int j) { return (double)(1.0*dp[j]-1.0*dp[k])/(1.0*y[k+1]-1.0*y[j+1]); } int main() { freopen("buy.in","r",stdin); freopen("buy.out","w",stdout); scanf("%I64d",&n); for (int i=1;i<=n;i++) scanf("%I64d%I64d",&node[i].x,&node[i].y); sort(node+1,node+n+1,cmp); for (int i=1;i<=n;i++) { while (tot&&node[i].y>=y[tot]) tot--; x[++tot]=node[i].x; y[tot]=node[i].y; } int head=1,tail=0; q[++tail]=0; for (int i=1;i<=tot;i++) { while (head<tail&&xielv(q[head],q[head+1])<x[i]) head++; int tmp=q[head]; dp[i]=dp[tmp]+x[i]*y[tmp+1]; while (head<tail&&xielv(q[tail],i)<xielv(q[tail-1],q[tail])) tail--; q[++tail]=i; } printf("%I64d",dp[tot]); return 0; }
滑(fa)雪
tony在一片雪地里滑雪,他从(1,1)出发,并只能从高的地方滑到低的地方,贪玩的tony想知道他到底能滑多远呢?
Input:
第一行两个数n,m表示雪地大小。
接下来n行每行m个数表示雪地,其中w[i][j] = x表示在i,j位置的高度为x,每个位置(除了边界)都可以滑到它的上下左右四个方向(从高往低)。
很基础的dp问题数据过小直接记忆化搜索
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn=305; const int zl[4][2]={{0,1},{0,-1},{-1,0},{1,0}}; int jz[maxn][maxn],ans,f[maxn][maxn]; int max(int a,int b) { if (a>b) return a; return b; } int n,m; int find(int x,int y) { int rt=0; if (f[x][y]>0) return f[x][y]; for (int i=0;i<=3;i++) { int xx=x+zl[i][1]; int yy=y+zl[i][0]; if (xx>=1&&xx<=n&&yy>=1&&yy<=m&&jz[xx][yy]<jz[x][y]) rt=max(rt,find(xx,yy)); } return f[x][y]=rt+1; } int main() { freopen("slide.in","r",stdin); freopen("slide.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&jz[i][j]); ans=find(1,1); printf("%d\n",ans); return 0; }
tom想知道,把一个整数n划分为若干个正整数的形式,一共有多少种方案。例如当n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};
input:
一行一个数n。
Output:
一行一个数表示方案数。
这道题有点傻逼啊记下了i这个数分成j个结果没有去重全wa非常开心
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn=5005; const int Mod=1e9+7; int dp[maxn][maxn]; int n; int main() { freopen("divide.in","r",stdin); freopen("divide.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) dp[i][1]=1; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { if (i==j) dp[i][j]=1+dp[i][i-1]; else if (i<j) dp[i][j]=dp[i][i]; else dp[i][j]=dp[i-j][j]+dp[i][j-1]; dp[i][j]%=Mod; } printf("%d\n",dp[n][n]); return 0; }斜率优化证明有点夸张但是nlogn的决策单调性又不算很好写(