七夕祭

做题时间:2021.02.02

\(【题目描述】\)

给出一个\(N \times M(N,M \leq 10^5)\)的矩阵,给出\(T(T \leq \min\{NM,10^5\})\)个目标点的坐标\((x_i,y_i)\)。每一次操作可以将相邻的两个点交换,问最少交换多少次才能使得每一行的目标点数相同(输出row)或者每一列的目标点数相同(输出column),亦或者两者都满足(输出both)。

\(【输入样例】\)

2 3 4
1 3
2 1
2 2
2 3

\(【输出样例】\)

row 1

\(【考点】\)

贪心、数学

\(【做法】\)



\(【代码】\)

#include<cstdio>
#include<iomanip>
#include<algorithm>
#define int long long//记得开long long 
using namespace std;
const int N=1e5+50;
int x[N],y[N];
int a[N],b[N];
int sum[N],ave;
int n,m,t,ans;
bool q;
inline int Abs(int a)
{
    if(a>0) return a;
    return -a;
}
void Change_Row()//求解行 
{
    ave=t/n;
    q=true;
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]-ave;//求出前缀和 
    sort(sum+1,sum+1+n);//升序排列 
    int k=(n+1)>>1;//找到中间的位置
    for(int i=1;i<=n;i++) ans+=Abs(sum[i]-sum[k]);//求解 

}

void Change_Col()//求解列 
{
    ave=t/m;
    q=true;
    for(int i=1;i<=m;i++) sum[i]=sum[i-1]+b[i]-ave; 
    sort(sum+1,sum+1+m);
    int k=(m+1)>>1;
    for(int i=1;i<=m;i++) ans+=Abs(sum[i]-sum[k]);

}
signed main()
{
    scanf("%lld%lld%lld",&n,&m,&t);
    for(int i=1;i<=t;i++){
        scanf("%lld%lld",&x[i],&y[i]);
        a[x[i]]++,b[y[i]]++;
    }
    if(t%m==0&&t%n==0){//摊点数能够被行和列平分 
        printf("both ");
        Change_Col();
        Change_Row();
    }
    else{
        if(t%n==0) printf("row "),Change_Row();
        if(t%m==0) printf("column "),Change_Col();
    }
    if(!q){
        printf("impossible\n");
        return 0;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2021-02-04 10:01  lxzy  阅读(81)  评论(0)    收藏  举报