【环形均分纸牌】 七夕祭

传送门

题意

会场由\(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);
}

posted @ 2020-07-12 15:25  Hyx'  阅读(130)  评论(0编辑  收藏  举报