18寒假13测

 

题目名称

buy

slide

divide

输入

buy.in

slide.in

divide.in

输出

buy.out

slide.out

divide.out

每个测试点时限

1秒

1秒

1秒

内存限制

256MB

256MB

256MB

测试点数目

10

10

10

每个测试点分值

10

10

10

是否有部分分

题目类型

传统

传统

传统

 

 

buy

description:

        地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最长的宽。土地的长和宽是不能交换的,例如一块2*5的土地和一块5*2的土地放在一起,价格为5*5=25。ZXR想知道最少花费多少钱可以买下所有的土地。

Input:

        第一行一个数n表示一共有n块土地。

            接下来n行每行两个数xi和yi分别表示每块土地的长和宽。

Output:

        一行一个数表示最小价格。

Sampleinput:

4

100 1

15 15

20 5

1 100

Sampleoutput:

    500

zxr分3组买这些土地:

第一组:100x1,

第二组1x100,

第三组20x5 和 15x15 plot.

每组的价格分别为100,100,300, 总共500.

HINT:

        对于30%的数据:n<=2000。

            对于100%的数据:n<=50000,长宽<=1e6

 

题解:先按x升序排序,再在此基础上按y降序排序,如果不满足此规则的点,则可以被覆盖,如:

X: 20 40 60

Y;50 25 46 显然二号点是没有用的,他可被三号节点覆盖;

于是我们得到了一个所有点都有用的序列,并且x,y的大小有序;

dp[i]表示选了1到 i 个点, dp[i] = dp[j] + Xi Yj+1 ,由这个形式我们可以想到斜率优化:如果有k>=j 并且k更优,则之后一定不会再用到j, k一定更优,通过转移方程得到:

dp[j] + Xi Yj+1 >= dp[k] +Xi Yk+1 , k>j

所以满足Xi >= (dp[k]-dp[j]) /(Yj+1 - Yk+1) 则k可跟新j,因为Xi递增,于是斜率越大越好, 所以我们就维护一个上凸包,使斜率满足上式且递增,则队首元素最优 

#include <bits/stdc++.h>
using namespace std;

const int maxn = 50000+5;
const long long inf = 100000000000008;
long long dp[maxn];
int qq[maxn];
int n;
inline void read(long long &x){
    x=0;long long f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 
    while(s>='0'&& s<='9'){x=x*10+s-'0';s=getchar();} 
    x*=f;
}
struct Point{
    long long  x, y;
}p[maxn],q[maxn];
bool cmp(Point a, Point b){
    return a.x == b.x ? a.y > b.y : a.x < b.x; 
} 

int main(){
    freopen("buy.in","r",stdin);
    freopen("buy.out","w",stdout);
    scanf("%d",&n);
    int hd = 1;
    for(int i = 1; i <= n; i++)
        read(p[i].x), read(p[i].y);
    sort(p + 1, p + 1 + n, cmp);
    q[1] = p[1];
    for(int i = 1; i <= n; i++){
        while(hd && p[i].y >= q[hd].y)
            hd--;
        q[++hd] = p[i];
    }
        
    int h = 1, t = 1, s = 1;
    qq[1] = 0;
    for(int i = 1; i <= hd; i++){
        while(h < t && q[i].x * (q[qq[h]+1].y - q[qq[h+1]+1].y) > dp[qq[h+1]] - dp[qq[h]])
            h++;
        
        dp[i] = q[qq[h]+1].y * q[i].x + dp[qq[h]];
        while(h < t && (q[qq[t-1]+1].y - q[qq[t]+1].y) * (dp[i] - dp[qq[t]]) >= (dp[qq[t]] - dp[qq[t-1]]) * (q[qq[t]+1].y- q[i+1].y))
            t--;
        qq[++t] = i;
    }
    printf("%I64d
",dp[hd]);
}

斜率优化要注意:加减符号和中间的变号过程; 斜率递增建下凸包,递减建上凸包

 

slide

description:

        tony在一片雪地里滑雪,他从(1,1)出发,并只能从高的地方滑到低的地方,贪玩的tony想知道他到底能滑多远呢?

Input:

        第一行两个数n,m表示雪地大小。

            接下来n行每行m个数表示雪地,其中w[i][j] = x表示在i,j位置的高度为x,每个位置(除了边界)都可以滑到它的上下左右四个方向(从高往低)。

Output:

        一行一个数表示滑行的最长长度。

Sample input:

22

4 3

21

Sample output:

3

Hint:对于30%的数据,n<=10,m<=10;

对于100%的数据,n<=300,m<=300。W[i][j]<=1e6;

题解:记忆化搜索的水题

#include <bits/stdc++.h>
using namespace std;

const int maxn = 305;
int n,m;
int mp[maxn][maxn],dp[maxn][maxn];
int a[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
int dfs(int x, int y){
    if(dp[x][y]) return dp[x][y];
    dp[x][y] = 1;
    int tmp = 0;
    for(int i = 0; i < 4; i++){
        int nx = x + a[i][0], ny = y + a[i][1];
        if(mp[nx][ny] < mp[x][y] && nx && ny && nx <=n &&ny <= m)
            tmp = max(tmp, dfs(nx, ny));
    }    
    return dp[x][y] += tmp;
}
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",&mp[i][j]);
    dfs(1, 1);
    printf("%d
",dp[1][1]);
}

divide

description:

        tom想知道,把一个整数n划分为若干个正整数的形式,一共有多少种方案。例如当n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

input:

        一行一个数n。

Output:

        一行一个数表示方案数%1e9+7。

Sample input:

4

Sample output:

5

Hint:

对于30%的数据,n<=50。

对于100%的数据,n<=5000。

题解:dp[i][j]表示i拆分成的数中最大的数是j;

   i > j, dp[i][j] = dp[i-j][j] + dp[i][j-1] //有两种情况,一是我选择拆分的数中有j, 二是选择的数中不含j

   i < j, dp[i][j] = dp[i][i] //之后会用到,意义也解释的通

   i == j, dp[i][j] = 1 + dp[i][j-1]

#include <bits/stdc++.h>
using namespace std;

const int mod = 1e9+7;
const int maxn = 5005;
int ans,t, dp[maxn][maxn];

int main(){
    freopen("divide.in","r",stdin);
    freopen("divide.out","w",stdout);
    int n;
    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];
            if(i > j)dp[i][j] = dp[i-j][j] + dp[i][j-1];
            if(i < j)dp[i][j] = dp[i][i];
            dp[i][j] %= mod;
        }
    printf("%d
",dp[n][n]);
    
}
原文地址:https://www.cnblogs.com/EdSheeran/p/8491674.html