神仙題(雖然是例題)
這道題目有一個很是重要的性質就是,只會改變相鄰的兩個數的位置,所以咱們交換兩個數,
只會改變一行的喜好小攤或者一列的喜好小攤,而不會同時改變行和列的喜好小攤,既然這樣的話,
咱們就能夠將這道題目分紅兩個部分,一部分是求行的最少次數,一部分是求列的最少次數。spa
這道題就是環形的均分紙牌(作法相同都是求出與目標答案的差值),經過記錄前綴和,而後排序
直接取在中位數上的一道神仙題調試
本題融合了「貨倉選址」和「均分紙牌」,是一道不錯的題目code
複製\(checkr()\)寫\(checkc()\)忘了把n改爲m了,咕咕咕
並且我以爲我對\(r\)和\(c\)有點搞不清楚,就像二分的\(l,r\)同樣排序
醜陋不堪,有不少調試用的宏,不喜勿噴ci
#include<bits/stdc++.h> #define int long long int #define fre //#define couts //#define zong //#define heng using namespace std; const int N=100000+2019; int row[N],column[N],r,c,ans1,ans2,n,m,t; int flagr,flagc; int s[N];//前綴和 #ifndef zong int checkr() { //處理橫排 memset(s,0,sizeof(s)); if(t%n!=0) return 0; r/=n;//求平均數 for(int i=1; i<=n; ++i) { row[i]-=r,s[i]=s[i-1]+row[i];//作差,求前綴和 } sort(s+1,s+1+n); int mid=(1+n)>>1; for(int i=1; i<=n; ++i) ans1+=abs(s[i]-s[mid]); //直接取中位數求答案便可 return 1; } #endif #ifndef heng int checkc() { //處理縱排 memset(s,0,sizeof(s)); if(t%m!=0) return 0; c/=m;//求平均數 for(int i=1; i<=m; ++i) { column[i]-=c,s[i]=s[i-1]+column[i];//作差,求前綴和 } sort(s+1,s+1+m); int mid=(1+m)>>1; for(int i=1; i<=m; ++i) ans2+=abs(s[i]-s[mid]); //直接取中位數求答案便可 return 1; } #endif signed main() { #ifndef fre freopen("a.in","row",stdin); freopen("a.out","w",stdout); #endif cin>>n>>m>>t; for(int i=1; i<=t; ++i) { int x,y; scanf("%lld%lld",&x,&y); row[x]++,column[y]++; r++,c++; } flagr=checkr(); flagc=checkc(); #ifndef couts if(flagc&&flagr) cout<<"both"; else if(flagr) cout<<"row"; else if(flagc) cout<<"column"; else cout<<"impossible"; #endif if(flagr||flagc) cout<<" "<<ans1+ans2; return 0; }