平时二测

一场摸你赛

2018722

(请选手务必仔细阅读本页内容)

一.题目概况

中文题目名称

开会

围墙

搬砖

英文题目名称

CP

gfw

bricks

可执行文件名

CP

gfw

bricks

输入文件名

CP.in

gfw.in

bricks.in

输出文件名

CP.out

gfw.out

bricks.out

每个测试点时限

1秒

1秒

1秒

测试点数目

10

10

10

每个测试点分值

10

10

10

题目类型

传统

传统

传统

二.提交源程序文件名

对于pascal语言

CP.pas

gfw.pas

bricks.pas

对于C语言

CP.c

gfw.c

bricks.c

对于C++语言

CP.cpp

gfw.cpp

bricks.cpp

三.运行内存限制

内存上限

512M

512M

512M

四.注意事项

1、  文件名(程序名和输入输出文件名)可能是大写的,以上面的表格为准。

2、  C/C++中函数main()的返回值类型必须是int,程序正常结束时的返回值必须是0。

 

开会

(CP.pas/c/cpp)

【问题描述】

开会,是对所有人时间的浪费,是对集体的谋杀。

山区学校的一些学生之间的关系似乎好得有点过头,以至于传出了一些(在风纪委员们看来)不好的绯闻。具体地,有n个学生,n-1条绯闻,每条绯闻的主角都是俩学生。记者们的恶趣味保证任意两个学生,可以通过若干条绯闻直接或间接地联系在一起。

于是学校打算邀请一些学生参加座谈会。

校长相信,假如邀请了某位学生x来开会,那么就能够震慑到x本人,以及和x在同一条绯闻里的学生们。

矿泉水是宝贵的,校长想知道最少需要请多少人来开会,才有可能震慑到所有同学。

【输入】

第一行是 n 表示学生数。

之后n-1行,每行俩整数x,y,表示学生x和y之间有绯闻。( x≠y,但不一定x<y )

 

【输出】

 一行,一个整数表示最少要邀请多少人。

 

【输入输出样例】

CP.in

CP.out

5

1 3

5 2

4 3

3 5

 

2

 

【数据范围】

对于前10%的数据,n<=15

对于前30%的数据,n<=2000

对于接下来30%的数据,n<=10^5,且有俩学生需要通过n-1条绯闻才能扯上关系。

对于前100%的数据,n<=10^5,1<=x,y<=n

【样例解释】

可以选择邀请学生2&3,或者是邀请学生3&5

围墙

(gfw.pas/c/cpp)

【问题描述】

天台的围栏不知道为啥被人破坏了。

卓司教主为了他的信徒能够放心地起舞,决定用自己从中央之国买来的GFW(GirlFriends Wallpaper)来把天台围上。

天台可以看作一个周长为C的圆,教主有n张gfw。为了美观,教主在从空中考察天台之后决定,对于第i张gfw(它有着L_i的长度),要使用的话左端必须位于位置X_i(从圆上的一个定点顺时针出发走X_i所到达的位置,显然定点在哪没影响)。

为了节能环保,教主希望用最少的gfw覆盖这个圆。圆上的某个位置可以被多张gfw覆盖。

【输入格式】

第一行俩整数C和n,表示周长和gfw的数量。

接下来n行,每行俩整数,第i行的数分别表示X_i和L_i。

【输出格式】

    一行一个整数,表示最少需要多少张gfw。

【输入输出样例】

gfw.in

gfw.out

5 3
0 1

1 2

3 3

2

 

【数据范围】

    对于前15%的数据,保证C,n<=200

对于接下来10%的数据,保证C<=50,n<=10^5

对于接下来20%的数据,保证C<=1000,n<=1000

对于接下来35%的数据,保证C,n<=10^5,

对于100%的数据,保证C<=10^9,n<=10^5,0<=X_i<C,1<=L_i<=C

【样例解释】

选择第2,3张gfw。 第二张覆盖了[1,3],第三张覆盖了[3,5]和[0,1]

 

搬砖

(bricks.pas/c/cpp)

【问题描述】

燕子飞到温暖的南方去了。

分别后的十年里,小N孤身在家乡生活,迫于生计而找了份搬砖的工作(等等这什么鬼)。

共有n个工地,第i个工地和第i+1个直接相连(1<=i<n),工地1和n并不直接相连。

从工地i走到i+1或者从i+1走到i都需要耗费1点时间。

有m个运输任务,第i个要求小N把砖头从工地L_i运到R_i。

天才的小N有了个绝妙的主意,假如在工地X和Y之间搞个传送站,那么在X可以直接不需要时间地到Y(Y到X也一样)。

因为预算限制,小N最多建一个传送站。

小N想通过合理地放置传送站,使得所有运输任务所需时间的最大值最小。

【输入格式】

    第一行两个整数n,m,分别表示n个工地,m个运输任务。

    接下来m行,其中第i行俩整数L_i,R_i。

【输出格式】

    输出一行,一个整数,表示可能的最小的 任务所需时间最大值。

【输入输出样例】

bricks.in

bricks.out

5 2

1 3

2 4

1

【数据范围】
       对于前15%的数据,保证n,m<=200

对于接下来10%的数据,保证n<=50,m<=10^5

对于接下来10%的数据,保证n<=1000,m<=1000

对于接下来35%的数据,保证n,m<=10^5,

对于100%的数据,保证n<=10^8,m<=10^5

题解:

第一题:原题

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

const int M = 1e5 + 10 ;
int h[M], dep[M], fa[M], tot, col[M];
struct edge{int nxt, v;}G[M << 1];
void add(int u, int v){
    G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot;
}
void dfs(int u, int f){
    fa[u] = f;
    dep[u] = dep[f] + 1;
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        dfs(v, u);
    }
}
struct node{
    int id, dep;
    bool operator < (const node &rhs) const {
        return dep < rhs.dep; 
    }
};
priority_queue <node> Q;
int main(){
    freopen("CP.in","r",stdin);
    freopen("CP.out","w",stdout);
    int n, cnt = 0;
    scanf("%d",&n);
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    dfs(1, 1);
    for(int i = 1; i <= n; i++)
        Q.push((node){i, dep[i]});
    while(!Q.empty()){
        int u = Q.top().id; Q.pop();
        if(col[u])continue;
        int z = fa[u];
        col[z] = 1;
        cnt++;
        for(int i = h[z]; i; i = G[i].nxt){
            int v = G[i].v;
            col[v] = 1;
        }
    }
    printf("%d\n", cnt);
} 
View Code

第二题:环上的区间覆盖;我们把环复制两倍,所以只要我们的线段覆盖了C---2*C就可以了(这里我们强制每个点都走到2*C)

首先我们先把没有用的线段删除,然后把剩下的线段复制一遍(相当于后移C步),此时线段的l, r一定是递增的;

我们统计的答案就是:未复制前的线段刚好可以跨过第一个终点C,他走的最后一个终点2*C需要的最少线段;

一般的区间覆盖,确定了起点,后面的选择一定是一定的,我们二分处理每条线段的下一条线段是哪条nxt;

然后统计每个线段跳几步到第二个终点f, 和他结束的线段; ans = min(f[ i ] - (i 又回到了i 对应的线段) )i 属于未复制的线段

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

const int M = 1000005;
int C, n, ans = 2e9;
struct Point{int l, r, len, id;}p[M], q[M];
bool cmp(Point A, Point B){
    if(A.l == B.l)return A.len > B.len;
    return A.l < B.l;
}
int f[M], g[M], nxt[M], cnt;
int main(){
    freopen("gfw.in","r",stdin);
    freopen("gfw.out","w",stdout);
    scanf("%d%d", &C, &n);
    for(int i = 1; i <= n; i++){
        scanf("%d%d", &p[i].l, &p[i].len);
        p[i].r = p[i].len + p[i].l; 
    }
    sort(p + 1, p + 1 + n, cmp);
    int lst = 1;
    q[++cnt] = p[1];
    for(int i = 2; i <= n; i++){
        if(p[i].r > p[lst].r)q[++cnt] = p[i], lst = i;
    }
    for(int i = 1; i <= cnt; i++)q[i + cnt].l = q[i].l + C, q[i + cnt].r = q[i].r + C;
    for(int i = 1; i <= (cnt<<1); i++){
        int lf = i, rg = cnt<<1, ans;
        while(lf <= rg){
            int mid = (lf + rg) >> 1;
            if(q[mid].l <= q[i].r)ans = mid, lf = mid + 1;
            else rg = mid - 1;
        }
        nxt[i] = ans;
    }
    for(int i = (cnt<<1); i; i--)
        if(q[i].r >= (C<<1))f[i] = 1, g[i] = i;
        else f[i] = f[nxt[i]] + 1, g[i] = g[nxt[i]];
    for(int i = 1; i <= cnt; i++)
        if(q[i].r >= C) {
            ans = min(ans, f[i] - (i == g[i] - cnt));
            //printf("%d %d %d %d %d %d\n", f[i], i, cnt, q[cnt].r, C, g[i]);
        }
    printf("%d\n", ans);
}
View Code

第三题:二分性质明显,暴力就是去寻找一个x-y的区间;

x-y 的区间满足abs(x - L) + abs(y - R) <= mid;

我就做到这个地方卡了,然后二分乱压缩X,Y, 随机得分;

正解就是才学的线性规划,即使知道了我也不会去绝对值,上课白学了。。。

两个绝对值对应一个矩形,我们只需判段是否在这个区间有解即可;

约束条件是: L - R- mid <= x- y <= mid + L - R     L + R - mid <= x + y <= mid + L + R;

如果存在上述区间即可,因为上面的式子解出来在端点一定是整数,合法

#include<bits/stdc++.h>
using namespace std;
#define RG register
const int M = 1e5 + 10;
struct sta{
    int l, r, len;
}p[M];
bool cmp(sta A, sta B){
    if(A.len == B.len)return A.r > B.r;
    return A.len > B.len;
}
inline int ab(int a){return a >= 0 ? a : -a;}
int n, m, ans = 0;
bool check(int k){
    int a = -2e9, c = -2e9, b = 2e9, d = 2e9;
    for(int i = 1; i <= m && p[i].len > k; i++){
        a = max(a, p[i].l + p[i].r - k);
        b = min(b, p[i].l + p[i].r + k);
        c = max(c, p[i].l - p[i].r - k);
        d = min(d, p[i].l - p[i].r + k);
    }
    if(a > b || c > d)return 0;
    return 1;
    
}

int main(){
    freopen("bricks.in","r",stdin);
    freopen("bricks.out","w",stdout);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++){
        scanf("%d%d", &p[i].l, &p[i].r); 
        if(p[i].r < p[i].l)swap(p[i].l, p[i].r);
        p[i].len = p[i].r - p[i].l;
    }
    sort(p + 1, p + 1 + m, cmp);
    int lf = 0, rg = p[1].len;
    
    while(lf <= rg){
        int mid = (lf + rg) >> 1;
        if(check(mid))rg = mid - 1, ans = mid;
        else lf = mid + 1;
            //fprintf(stderr, "%d\n",mid);
    }    
    printf("%d\n", ans);
} 
View Code

猜你喜欢

转载自www.cnblogs.com/EdSheeran/p/9609711.html
今日推荐