dp day 4 斜率优化(fa)bzoj1597+简单dp问题

地主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的决策单调性又不算很好写( 懒癌晚期

猜你喜欢

转载自blog.csdn.net/beloved_rancy/article/details/79417583
dp4