BZOJ 3032 七夕祭

在这里插入图片描述
在这里插入图片描述
思路

  • 交换左右相邻的两个摊点,只会改变两列中的cl感兴趣的数量,对每行的数量不会造成影响,改变上下的也是相同的道理
  • 对于总数是否可可以被均分,决定了是否有解,即是:如果总数不能的被n整除,那么行上无解,不能被m整除,那么列上无解
  • 针对行和列,我们单独讨论,就行而言,我们把个点的元素减去平均值,最后我们通过操作要把每个点都变成0,用f存减去平均值以后的数组的前缀和,由于第一行和最后一行看做相邻的元素,那么就转换成了一个环,问题就转换成了在把f数组看做一个一个的地址,找一个点,使得这个点到每个点的距离最小,这个最小的点就是答案

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 100010;
typedef long long ll;

ll a[N], b[N];
int n, m, t;
ll f[N];

ll calc(ll *A, int n)
{
    ll ans = 0;
    memset(f, 0, sizeof f);
    for (int i = 1; i <= n; i++)
    {
        A[i] -= A[0] / n;
        f[i] = f[i - 1] + A[i];
    }

    sort(f + 1, f + n + 1);

    for (int i = 1; i <= n; i++)
    {
        ans += abs(f[i] - f[(n + 1) / 2]);
    }
    return ans;
}

int main()
{
    scanf("%d%d%d", &n, &m, &t);
    for (int i = 1; i <= t; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        a[x]++;
        b[y]++;
    }

    for (int i = 1; i <= n; i++)
        a[0] += a[i];
    for (int i = 1; i <= m; i++)
        b[0] += b[i];
    if (a[0] % n == 0 && b[0] % m == 0)
        printf("both %lld\n", calc(a, n) + calc(b, m));
    else if (a[0] % n == 0 && b[0] % m != 0)
        printf("row %lld\n", calc(a, n));
    else if (a[0] % n != 0 && b[0] % m == 0)
        printf("column %lld\n", calc(b, m));
    else
        puts("impossible");

    return 0;
}
发布了121 篇原创文章 · 获赞 223 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_45432665/article/details/104919800