【环形均分纸牌】 七夕祭
传送门
题意
会场由\(n\times m\)个摊位组成,cl 只对部分商品摊位感兴趣,使得所有cl 感兴趣的摊位各行各列中的一样多,调整方式只能交换相邻摊位,
两个摊位相邻当且仅当处于同一行或同一列的相邻位置,最后一行或列与第一列也是相邻的,求是否能满足行列一样多
如果行列都满足输出\(both\),满足行输出\(row\),满足列输出\(column\),如果都满足输出\(both\),都不满足输出\(impossible\)
如果能满足就输出最多的情况下求最小交换次数
数据范围
\(\begin{array}{l}1 \leq N, M \leq 100000 \\ 0 \leq T \leq \min (N \times M, 100000) \\ 1 \leq x \leq N \\ 1 \leq y \leq M\end{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\n",ans);
}