• 七夕祭⭐


    题面

    七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。

    于是TYVJ今年举办了一次线下七夕祭。

    Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩。

    TYVJ七夕祭和11区的夏祭的形式很像。

    矩形的祭典会场由N排M列共计N×M个摊点组成。

    虽然摊点种类繁多,不过cl只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。

    Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。

    不过zhq告诉Vani,摊点已经随意布置完毕了,如果想满足cl的要求,唯一的调整方式就是交换两个相邻的摊点。

    两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。

    由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。

    现在Vani想知道他的两个要求最多能满足多少个。

    在此前提下,至少需要交换多少次摊点。

    输入格式

    第一行包含三个整数N和M和T,T表示cl对多少个摊点感兴趣。

    接下来T行,每行两个整数x, y,表示cl对处在第x行第y列的摊点感兴趣。

    输出格式

    首先输出一个字符串。

    如果能满足Vani的全部两个要求,输出both;

    如果通过调整只能使得各行中cl感兴趣的摊点数一样多,输出row;

    如果只能使各列中cl感兴趣的摊点数一样多,输出column;

    如果均不能满足,输出impossible。

    如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

    数据范围

    1≤N,M≤100000,
    0≤T≤min(N∗M,100000),
    1≤x≤N,
    1≤y≤M
    

    输入样例:

    2 3 4
    1 3
    2 1
    2 2
    2 3
    

    输出样例:

    row 1
    

    题解

    这个题其实是两个问题:

    1.让摊点上下移动,使得每行的摊点一样多

    2.左右移动摊点,使得每列的摊点一样多

    两个问题是等价的,就讨论第一个

    r[i]表示每行的摊点数

    然后使得r[i]的一些摊点移动到r[i - 1]和r[i + 1], 类似于"均摊纸牌"

    均摊纸牌

    有M个人排一排,每个人分别有C[1]~C[M]张拍,每一步中,一个人可以将自己的一张手牌给相邻的人,求至少需要几步

    显然, 纸牌总数T能被M整除有解,在有解的情况下, 考虑第一个人:

    1.C[1] >= T/M, 第一个人要给第二个人C[1] - T/M张牌
    2.C[1] < T/M, 第二个给第一个人T/M - C[1]张牌
    本质就是使得第一人满足要求要|T/M - C[1]|步
    那么满足第二人就要 |T/M - (C[2] - (T/M - C[1]))| = |2 * T/M - (C[1] + C[2])|步
    满足第三人 |T/M - (C[3] - (T/M - (C[2] - (T/M - C[1]))))| = |3 * T/M - (C[1] + C[2] + C[3])|

    到这里就可以发现,有一段是前缀和, 但再仔细化简以下可以发现

    |3 * T/M - (C[1] + C[2] + C[3])|
    =|(T/M - C[1]) + (T/M - C[2]) + (T/M - C[3])|
    =|(C[1] - T/M) + (C[2] - T/M) + (C[3] - T/M)|

    我们可以让A[i] = C[i] - T/M, S[i]为A[i]的前缀和,

    那么对于"均摊纸牌"这道题的答案就是

    (sum^{n}_{i=1})|S[i]|

    对于本题来说,无非是变成了环形问题

    直接无脑dp就可以

    我们随便选取一个人k最为断环的最后一名(即第一个人变为为k + 1),

    则从这个人开始的持有的牌数(这行的摊点数), 前缀和为

    A[k + 1]   S[k + 1] - S[k]
    A[k + 2]   S[k + 2] - S[k]
    ...
    A[M]       S[M] - S[k]
    A[1]       S[M] - S[k] + S[1]
    A[2]       S[M] - S[k] + S[2]
    ...
    A[k]       S[M] - S[k] + S[k]
    

    我们发现S[M] = 0, 所以答案为

     |S[k + 1] - S[k]| + ... + |S[M] - S[k]| + |s[M] - S[k] + S[1]| + ... + |S[M] - S[K] + S[k]|

    =|S[k + 1] - S[k]| + ... + |S[M] - S[k]| + |-S[k] + S[1]| + ... + |-S[k] + S[k]|

    =(sum^{n}_{i=1}) |S[i] - S[k]|

    答案已经很明显了,像不像"仓货选址"?

    仓货选址

    一条轴上有N家店,每家店的坐标为D[1]~D[N],选择一家点为仓库向其他商店发货,求选哪家店,运送距离最短

    不就是(sum^{n}_{i=1}) |D[i] - D[k]| 为答案吗?

    当然是选中位数了啦,

    设k左边有P家店,右边有Q家店

    如果P<Q,那必然将k右移, ans - Q + P,答案明显变小了

    Q>P,同理,故选择中位数

    所以本题的答案就已经近在眼前了, 前缀和,求中位数

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1e5 + 5;
    
    int n, m, k;
    int c[maxn], r[maxn], s[maxn];
    
    ll work(int a[], int n)
    {
        for (int i = 1; i <= n; ++i)
            s[i] = s[i - 1] + a[i] - k / n;
        sort(s + 1, s + 1 + n);
        ll ans = 0;
        for (int i = 1; i <= n; ++i)
            ans += abs(s[i] - s[(n >> 1) + 1]);
        return ans;
    }
    
    int main()
    {
        cin >> n >> m >> k;
        for (int i = 1; i <= k; ++i)
        {
            int a, b; cin >> a >> b;
            ++c[b], ++r[a];
        }
        if (k % n + k % m == 0)
            cout << "both " << work(c, m) + work(r, n);
        else if (k % n == 0)
            cout << "row " << work(r, n);
        else if (k % m == 0)
            cout << "column " << work(c, m);
        else cout << "impossible";
        return 0;
    }
    
  • 相关阅读:
    PowerDesigner生成sql及说明文档
    Visual Studio 2005 Team System & UML
    检查数据库数据字段命名规范与合法性的脚本
    常用的快速Web原型图设计工具
    用户需求说明书模板
    数据库设计说明书
    Visual SourceSafe 命名约定和限制
    需求管理工具DOORS介绍
    C#编码命名规则
    数据库对象命名规范
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/12852367.html
Copyright © 2020-2023  润新知