七夕祭
做题时间: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;
}

浙公网安备 33010602011771号