• NOIP模拟 17.8.16


    NOIP模拟17.8.16

    A 债务
    文件名 输入文件 输出文件 时间限制 空间限制
    debt.pas/c/cpp debt.in debt.out 1s 128MB
    【题目描述】
    小 G 有一群好朋友,他们经常互相借钱。假如说有三个好朋友 A,B,C。A
    欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元。小 G 是个追求简约的人,
    他觉得这样的债务太繁杂了。他认为,上面的债务可以完全等价为 A 欠 C 20 元,
    B 既不欠别人,别人也不欠他。这样总债务规模就压缩到了 20 元。
    现在给定 n 个人和 m 条债务关系。小 G 想找到一种新的债务方案,使得每个
    人欠钱的总数不变,或被欠钱的总数不变(但是对象可以发生变化),并且使得总
    债务规模最小。
    【输入格式】
    输入文件第一行两个数字 n, m,含义如题目所述。
    接下来 m 行,每行三个数字 ai
    , bi, ci,表示 ai 欠 bi 的钱数为 ci。
    注意,数据中关于某两个人 A 和 B 的债务信息可能出现多次,将其累加即可。
    如”A 欠 B 20 元”、”A 欠 B 30 元”、”B 欠 A 10 元”,其等价为”A 欠 B 40 元”。
    【输出格式】
    输出文件共一行,输出最小的总债务规模。
    【样例输入 1】
    5 3
    1 2 10
    2 3 1
    2 4 1
    【样例输出 1】
    10
    【样例输入 2】
    4 3
    1 2 1
    2 3 1
    3 1 1
    【样例输出 2】
    0
    【数据范围】
    对于 30% 的数据,1 ≤ n ≤ 10,1 ≤ m ≤ 10。
    对于 60% 的数据,1 ≤ n ≤ 100, 1 ≤ m ≤ 104。
    对于 80% 的数据,1 ≤ n ≤ 104,1 ≤ m ≤ 104。
    对于 100% 的数据,1 ≤ n ≤ 106,1 ≤ m ≤ 106。
    对于所有的数据,保证 1 ≤ ai, bi ≤ n, 0 < ci ≤ 100。

    【题解】

    水题,略,注意细节,想清楚

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 
     6 const int MAXN = 100 + 10;
     7 
     8 inline void read(int &x)
     9 {
    10     x = 0;char ch = getchar(), c = ch;
    11     while(ch < '0' || ch > '9')c = ch, ch = getchar();
    12     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
    13     if(c == '-')x = -x;
    14 }
    15 
    16 char s[MAXN][MAXN];int n, ok;
    17 
    18 int check(int x, int y)
    19 {
    20     if(s[x][y] == '.')return 0;
    21     if(x == n || x == n - 1)return 1;
    22     if(y == 1 || y == n)return 1;
    23     if(s[x + 1][y] == '.' || s[x + 2][y] == '.' || s[x + 1][y - 1] == '.' || s[x + 1][y + 1] == '.')return 1;
    24     s[x][y] = s[x + 1][y] = s[x + 2][y] = s[x + 1][y - 1] = s[x + 1][y + 1] = '.';
    25     return 0;
    26 }
    27 
    28 int main()
    29 {
    30     read(n);
    31     for(register int i = 1;i <= n;++ i) scanf("%s", s[i] + 1);
    32     for(register int i = 1;i <= n;++ i)
    33     {
    34         for(register int j = 1;j <= n;++ j)
    35             if(check(i, j))
    36             {
    37                 ok = 1;
    38                 break;
    39             }
    40         if(ok)break;
    41     }
    42     if(ok)printf("NO");
    43     else printf("YES");
    44     return 0;
    45 }
    T1

    B 小 Z 搭积木
    文件名 输入文件 输出文件 时间限制 空间限制
    box.cpp box.in box.out 2s 128MB
    【题目描述】
    小 Z 喜欢搭积木。小 Z 一共有 n 块积木,并且积木只能竖着一块一块的摞,可
    以摞多列。小 Z 的积木都是智能积木,第 i 块积木有一个情绪值 Xi。当摞在该积
    木上面积木总数超过 Xi 时,i 号积木就会不高兴。小 Z 情商这么高,肯定不希望
    有积木不高兴。但是他又希望每块积木都被用上,并且摞的积木列的总数最少。你
    能帮帮萌萌的小 Z 吗?
    【输入格式】
    输入文件第一行一个数字 n,含义如题目所述。
    第 2 行一共 n 个数,第 i 个数为 Xi,含义如题目所述。
    【输出格式】
    输出一个数字,表示最小的积木列数目。
    【样例输入 1】
    3
    0 0 10
    【样例输出 1】
    2
    4
    【样例输入 2】
    4
    0 0 0 0
    【样例输出 2】
    4
    【数据范围】
    30% 数据,1 ≤ n ≤ 10
    60% 数据,1 ≤ n ≤ 100
    80% 数据,1 ≤ n ≤ 1000
    100% 数据,1 ≤ n ≤ 5000
    对于所有数据点,都有 Xi ≤ n

    【题解】

    我的方法是二分答案降序贪心放。

    标解是这样的:

    先将所有的盒子按照承载量从小到大排序。然后我们开一个数组,

    记录一下当前一共有多少列,每一列一共有多少个盒子。从小到

    大扫描所有的盒子,找到能放下的数量最多的列,放进去。如果没

    有任何一列能放下,则建一个新列。 ——SD Ag爷 ty哥哥

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define min(a, b) ((a) < (b) ? (a) : (b))
    
    const int MAXN = 5000 + 10;
    
    inline void read(int &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9')c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
        if(c == '-')x = -x;
    }
    
    int n, x[MAXN], ans, cnt[MAXN];
    
    int check(int now)
    {
        memset(cnt, 0x3f, sizeof(cnt));
        int p = 1, ok = 1;
        while(p <= n)
        {
            ok = 1;
            for(register int i = 1;i <= now;++ i)
            {
                if(!cnt[i])continue;
                cnt[i] = min(cnt[i] - 1, x[p]), ++p, ok = 0;
            }
            if(ok)return 0;
        }
        return 1;
    }
    
    int main()
    {
        read(n);
        for(register int i = 1;i <= n;++ i) read(x[i]);
        std::sort(x + 1, x + 1 + n, std::greater<int>());
        register int l = 1, r = n, mid;
        while(l <= r)
        {
            mid = ((l + r) >> 1);
            if(check(mid))r = mid - 1;
            else l = mid + 1;
        } 
        printf("%d", l);
        return 0;
    }
    T2

    C 分宿舍
    文件名 输入文件 输出文件 时间限制 空间限制
    love.cpp love.in love.out 1s 128MB
    【题目描述】
    A 校有着神奇的住宿制度,不分男女宿舍,所有 n 个学生被统一分到两栋宿舍
    楼中。作为年轻人,学生之间心生爱慕之情是很正常。我们用爱慕值来表示两名学
    生之间的爱慕程度,如果两名爱慕值为 c 的学生被安排在同一宿舍楼,他们或她们
    便会在一起,并造成影响力为 c 的早恋事件。
    每年年末,身为政教处主任的你会将所有早恋事件按照影响力从大到小排成一
    个列表,然后上报给校长。公务繁忙的校长只会去看列表中第一个事件的影响力,
    如果影响很大,他会考虑撤换政教处主任。
    在详细考察了 n 个学生之间的爱慕关系后,你觉得压力很大。你要合理的将学
    生们分到两栋宿舍,以求产生的早恋事件影响力都比较小,以保住自己的官职。假
    设只要处于同一栋宿舍楼的两个人之间有爱慕关系,他们就一定会在这年的某个时
    候在一起。
    那么,要怎么分配,才能让校长看到的那个早恋事件的影响力最小呢?这个最
    小值是多少?
    【输入格式】
    第一行两个整数 n 和 m,分别表示学生的数目和爱慕关系的对数。
    接下来 m 行,每行为 3 个正整数 ai,bi,ci,表示学生 ai 和 bi 之间有爱慕关
    系,爱慕值为 ci。
    数据保证 1 ≤ ai ≤ bi ≤ n,0 < ci ≤ 109,且每对爱慕关系只出现一次。
    【输出格式】
    输出一个数,为通过合理安排,校长看到的那个早恋事件的最小影响力。如果
    没有发生早恋事件,输出 0。
    6
    【样例输入】
    4 6
    1 4 2534
    2 3 3512
    1 2 28351
    1 3 6618
    2 4 1805
    3 4 12884
    【样例输出】
    3512
    【数据范围】
    对于 30% 的数据,n ≤ 15。
    对于 70% 的数据,n ≤ 2000,m ≤ 50000。
    对于 100% 的数据,n ≤ 20000,m ≤ 100000。

    【题解】

    并查集裸题。

    1. 普通并查集
    i表示第i个学生,i+n为虚拟节点,表示不能和i在一个宿舍的人
    若两个点在同一并查集中,说明它们必须被分到同一个宿舍楼
    将所有的爱慕关系从大到小排序
    若a和b在同一并查集中,则此时c为答案
    若不在同一并查集,令a与b+n所在并查集合并,b与a+n所在并查集合并
    2. 加权并查集
    同样将所有爱慕关系从大到小排序
    每个点存储额外信息type,type为0表示和父亲结点在同一个宿舍楼,1表示和父亲结点不在同一个宿舍楼
    合并与查询的方式类似食物链

    3. 二分+dfs
    二分答案
    对于比二分答案大的爱慕关系,建图,显然若该图可以黑白染色,该答案可行;反之不可行

    ——gty

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 
     7 const int MAXN = 20000 + 10;
     8 
     9 inline void read(int &x)
    10 {
    11     x = 0;char ch = getchar(), c = ch;
    12     while(ch < '0' || ch > '9')c = ch, ch = getchar();
    13     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
    14     if(c == '-')x = -x;
    15 }
    16 
    17 int n,m,fa[MAXN << 2],a[MAXN],b[MAXN],c[MAXN],cnt[MAXN];
    18 
    19 int find(int x)
    20 {
    21     return x == fa[x] ? x : fa[x] = find(fa[x]);
    22 } 
    23 
    24 int cmp(int a, int b)
    25 {
    26     return c[a] > c[b];
    27 }
    28 
    29 int main()
    30 {
    31     read(n), read(m);
    32     register int tmp1, tmp2, tmp3, p1, p2, pp1, pp2;
    33     for(register int i = (n << 1);i >= 1;-- i)fa[i] = i;
    34     for(register int i = 1;i <= m;++ i)read(a[i]), read(b[i]), read(c[i]), cnt[i] = i;
    35     std::sort(cnt + 1, cnt + 1 + m, cmp);
    36     for(register int i = 1;i <= m;++ i)
    37     {
    38         tmp1 = a[cnt[i]], tmp2 = b[cnt[i]], tmp3 = c[cnt[i]];
    39         p1 = find(tmp1 << 1), p2 = find(tmp2 << 1);
    40         pp1 = find(tmp1 << 1 | 1), pp2 = find(tmp2 << 1 | 1);
    41         if(pp1 == pp2)
    42         {
    43             printf("%d", tmp3);
    44             return 0;
    45         }
    46         fa[pp2] = p1;
    47         fa[pp1] = p2;
    48     }
    49     printf("0");
    50     return 0;
    51 }
    T3
  • 相关阅读:
    dialog draggable
    sql删除重复数据
    winform截取屏幕并发送邮件
    TreeView 一些总结
    省市互连
    查找 ASP.NET 进程的名称
    不错的sql面试题
    在javascript中获取用户控件里的子控件的值;另打开新窗口传值回原窗口
    根据日期显示星期几
    不想让别人使用电脑某个软件的小技巧
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7375194.html
Copyright © 2020-2023  润新知