zoukankan      html  css  js  c++  java
  • 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]);
        
    }
  • 相关阅读:
    提交一个spark程序及spark执行器
    前端如何让服务器主动向浏览器推送数据
    h5页面移动端iPhoneX适配方法
    详说tcp粘包和半包
    mysql配置文件 /etc/my.cnf 详细解释
    【todo】MVCC原理及与锁之间的关系
    【todo】innodb表锁的底层实现原理
    【todo】innodb行锁的底层实现原理
    【todo】mysql binlog
    [todo] spring 事务的传播性
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/8491674.html
Copyright © 2011-2022 走看看