Acwing 七夕祭 (前缀和+中位数+思维)

题面

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

于是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

思路

讲这个问题前我们有必要了解一下所谓的环形均分纸牌问题。就是有围成一圈的小朋友,他们的手里各自拿着一些纸牌,他们每次可以向左右两边传递一个纸牌,问最少多少次的传递可以使得纸牌被所有人均分。那么我们可以假设p[i]为第i个人向第i+1个人传递的纸牌数目。那么我们可以得到,p[i]=p[i-1]+a[i]-avg,avg是最后均摊得到的纸牌个数,这个很好理解,然后我们对这个式子进行一个递推,就得到p[i]就是a[i]-avg这个数组的前缀和在加上一个p[n](这个是递推的时候边界剩下的,读者可以自己推导一下)。那么我们要求的是所有的P[i]的绝对值之和,那么根据式子最终我们所需要的的答案就是前缀和数组的每一个元素和数轴上的一个元素的差的绝对值的累加最小值,那么这个点去前缀和数组的中位数的时候,式子最小,所以再进行一次求和运算就好了。

代码实现

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
const int maxn=100000+10;
int col[maxn],row[maxn];
int n,m,t;
int d[maxn];
typedef long long ll;
inline ll solve (int a[],int num) {
     ll ans=0;
     for (int i=1;i<=num;i++) ans+=a[i];
     int avg=ans/num;
     d[0]=0;
     for (int i=1;i<=num;i++) {
         d[i]=d[i-1]+a[i]-avg;
     }
     sort (d+1,d+num+1);
     ll sum=0;
     for (int i=1;i<=num;i++) {
        sum+=abs (d[i]-d[(num+1)/2]);
     }
     return sum;
}
int main () {
    cin>>n>>m>>t;
    for (int i=0,x,y;i<t;i++) {
        cin>>x>>y;
        ++row[x];
        ++col[y];
    }
    if (t%n&&t%m) cout<<"impossible"<<endl;
    else {
        if (t%n==0&&t%m==0) {           //只能均摊每一行
            cout<<"both"<<" ";
            cout<<solve (row,n)+solve (col,m)<<endl;
        }
        else if (t%m==0&&t%n) {     //可以均摊每一列
            cout<<"column ";
            cout<<solve (col,m)<<endl;
        }
        else  if (t%n==0&&t%m) {
            cout<<"row"<<" ";
            cout<<solve (row,n)<<endl;
        }
    }
    return 0;
}
posted @ 2020-07-16 15:41  Luglucky  阅读(169)  评论(0编辑  收藏  举报