传送门
题意
会场由(n imes m)个摊位组成,cl 只对部分商品摊位感兴趣,使得所有cl 感兴趣的摊位各行各列中的一样多,调整方式只能交换相邻摊位,
两个摊位相邻当且仅当处于同一行或同一列的相邻位置,最后一行或列与第一列也是相邻的,求是否能满足行列一样多
如果行列都满足输出(both),满足行输出(row),满足列输出(column),如果都满足输出(both),都不满足输出(impossible)
如果能满足就输出最多的情况下求最小交换次数
数据范围
(egin{array}{l}1 leq N, M leq 100000 \ 0 leq T leq min (N imes M, 100000) \ 1 leq x leq N \ 1 leq y leq Mend{array})
题解
-
交换左右两个相邻的只会改变两列中cl感兴趣的摊位个数
-
交换上下两个相邻的只会改变两行中cl感兴趣摊位的个数
所以可以将行和列分成两个独立的来计算
-
通过最少次数的左右交换使得每列中cl感兴趣的摊位数相同
-
通过最少次数的上下交换使得每行中cl感兴趣的摊位数相同
前缀和为(S_{k+1}-S_{k}, S_{k+2}- S_{k}, ldots, S_{N}-S_{k}, S_{1}+S_{N}-S_{k}, ldots, S_{N})
其中(S_{N}=0)恒成立,所以就是求一个(k)使得(sum_{i=1}^{N}|S_{i}-S_{k}|)最小
即环形均分纸牌,对行和列分别进行均分即可,时间复杂度为(O(n·logn+m·logm))
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,n) for(int i=a;i<n;i++)
int n,m,t;
const int N=1e5+10;
int r[N],c[N];
int sumr[N],sumc[N];
int main(){
scanf("%d%d%d",&n,&m,&t);
rep(i,0,t){
int x,y;
scanf("%d%d",&x,&y);
r[x]++;
c[y]++;
}
bool row=!(t%n),column=!(t%m);
if(row){
if(column) printf("both ");
else printf("row ");
}
else{
if(column) printf("column ");
else{
printf("impossible");
return 0;
}
}
ll ans=0;
if(row){
int avg=t/n;
rep(i,1,n+1) r[i]-=avg;
rep(i,1,n+1) sumr[i]=sumr[i-1]+r[i];
sort(sumr+1,sumr+n+1);
int mid=sumr[n+1>>1];
rep(i,1,n+1)
ans+=abs(sumr[i]-mid);
}
if(column){
int avg=t/m;
rep(i,1,m+1) c[i]-=avg;
rep(i,1,m+1) sumc[i]=sumc[i-1]+c[i];
sort(sumc+1,sumc+m+1);
int mid=sumc[m+1>>1];
rep(i,1,m+1)
ans+=abs(sumc[i]-mid);
}
printf("%lld
",ans);
}