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\n",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\n",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\n",dp[n][n]);
    
}

 

posted @ 2018-03-03 18:29  Ed_Sheeran  阅读(228)  评论(0)    收藏  举报