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]);

}

原文地址:https://www.cnblogs.com/EdSheeran/p/8491674.html

时间: 2024-11-09 02:47:31

18寒假13测的相关文章

18寒假12测

Day1 题目名称 party array treasure 输入 party.in array.in treasure.in 输出 party.out array.out treasure.out 每个测试点时限 1秒 1秒 1秒 内存限制 64MB 64MB 64MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 party 题目描述: 在M公司里,每个人只有一个直属上司(除了boss).这个公司举办派对,每个人可以给派

18寒假第一测

猪猪的想法输入文件:thought.in输出文件:thought.out时间限制:1 second空间限制:128 MB题目描述狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一个很有趣的事情--喜欢是可以传递的,例如猪猪喜欢猪猪,猪猪喜欢猪猪,那么可以说猪猪喜欢猪猪.有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险.现在给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出N

18寒假第二测

第一题:二维树状数组,bit[x][y]表示从(1,1)到(x,y)的和,二维的坐标从一维的推过来,正确性可以用一个递增和一个递减的序列单调性证明,至于构图就当黑箱吧 #include <cstdio> int n, m, q; struct Case1 { int bit[100010]; void modify( int p, int d ) { for( int i = p; i <= m; i += i & -i ) bit[i] += d; } int query( i

18寒假第三测

第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离 #include<bits/stdc++.h> using namespace std; const int maxn = 100015, P = 20; int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn]; void dfs(int u,int from){ //

18寒假第六测

第一题:乘法修改的线段树 一定不能将change,modify分类讨论定两个标记,会有顺序影响 lazy标记一定要long long,又忘了... 代码和上一次差不多 第二题:离散暴力,也可以扫描线 离散时要将格子映射成点,不然会出现以下情况: 算横着的小矩形宽就是2,算黄色面积宽还是2,因为没有2让3去减 如果映射成点,就像这样,,放图比较好理解,就像扫描线,一个叶子节点存的是一个左闭右开的区间 也可以离散+扫描线,但还没写出来 #include <bits/stdc++.h> using

18寒假第五测

第一题 线段树 树状数组存差b[i] = a[i]-a[i-1],反正是单点查询,我为什么没想到...很傻的用线段树 #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long int n, m, a[maxn]; struct SegmentTree{ struct node{ ll sum; int lazy; }; node Tree[maxn << 2]; #de

Day 18(06/13) 文件处理、函数

一.文件处理流程 二.基本操作 2.1 文件操作基本流程初探 2.2 文件编码 2.3 文件打开模式 2.4 文件内置函数flush 2.5 文件内光标移动 2.6 open函数详解 2.7 上下文管理 2.8 文件的修改 一.文件处理流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 二.基本操作 2.1 文件操作基本流程初探 f = open('chenli.txt') #打开文件 first_line = f.readline() print('first li

18.2.13 codevs1012 最大公约数和最小公倍数问题

1012 最大公约数和最小公倍数问题 2001年NOIP全国联赛普及组 题目描述 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件:  1.P,Q是正整数 2.要求P,Q以x0为最大公约数,以y0为最小公倍数. 试求:满足条件的所有可能的两个正整数的个数. 输入描述 Input Description 二个正整数x0,y0 输出描述 Output Description 满足条件的所有可

18.2.13 codevs1212 最大公约数

题目描述 Description 求两个数A和B的最大公约数. 1<=A,B<=2^31-1 输入描述 Input Description 两个整数A和B 输出描述 Output Description 最大公约数gcd(A,B) 样例输入 Sample Input 8 12 样例输出 Sample Output 4 1 #include <iostream> 2 #include<math.h> 3 4 using namespace std; 5 6 long di