【算法進階0x00】七夕祭

【題面】
           \;\;\;\;\;\,TYVJ七夕祭和11區的夏祭的形式很像。矩形的祭典會場由N排M列共計N×M個攤點組成。雖然攤點種類繁多,不過cl只對其中的一部分攤點感興趣,比如章魚燒、蘋果糖、棉花糖、射的屋……什麼的。Vani預先聯繫了七夕祭的負責人zhq,希望能夠通過恰當地佈置會場,使得各行中cl感興趣的攤點數一樣多,並且各列中cl感興趣的攤點數也一樣多。
           \;\;\;\;\;\,不過zhq告訴Vani,攤點已經隨意佈置完畢了,如果想滿足cl的要求,唯一的調整方式就是交換兩個相鄰的攤點。兩個攤點相鄰,當且僅當他們處在同一行或者同一列的相鄰位置上。由於zhq率領的TYVJ開發小組成功地扭曲了空間,每一行或每一列的第一個位置和最後一個位置也算作相鄰。現在Vani想知道他的兩個要求最多能滿足多少個。在此前提下,至少需要交換多少次攤點。


退役前一個月,希望能留下點東西。。。
【分析】
判斷橫行和縱列能否平均分就是判斷能否整除,這是我們下一步在行或者列將他們平分的前提
這裏有一道題叫獨木橋。通過這道題我們可以看到一個一般的性質。在沒有強制作標記的情形下,將兩個元素交換等於不做交換。而對於每一個操作相當於是橫縱座標+1或-1。

如上說法,我們可以把行的平分和列的平分單獨抽離出來。這就變成了將一個數軸中各個點的值平均分的問題。解決這類題目可以用解決糖果傳遞分金幣的方式去解決。列出n個等式,然後用一個單變量和確定的前綴和減平均值表示,從而用人類智慧(中位數)去解決


【code】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=1e5+1000;
int n,m,T;
int x[maxn],y[maxn];
inline void read(int &x){
	x=0;int fl=1;char tmp=getchar();
	while(tmp<'0'||tmp>'9'){if(tmp=='-')fl=-fl;tmp=getchar();}
	while(tmp>='0'&&tmp<='9')x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
	x=x*fl;
}
signed main(){
	cin>>n>>m>>T;
	for(int i=1;i<=T;i++){
		int t;read(t),x[t]++,read(t),y[t]++;
	}
	if(T%n==0){
		if(T%m==0)printf("both ");
		else printf("row ");
	}
	else{
		if(T%m==0)printf("column ");
		else{
			printf("impossible ");
			return 0;
		}
	}
	long long axe,mid,ans=0;
	if(T%n==0){
		axe=T/n;
		for(int i=1;i<=n;i++) x[i]+=x[i-1];
		for(int i=1;i<=n;i++) x[i]=axe*i-x[i];
		sort(x+1,x+n+1);
		mid=n+1>>1;
		for(int i=1;i<mid;i++) ans=ans+x[mid]-x[i];
		for(int i=mid+1;i<=n;i++) ans=ans+x[i]-x[mid];
	}
	if(T%m==0){
		axe=T/m;
		for(int i=1;i<=m;i++) y[i]+=y[i-1];
		for(int i=1;i<=m;i++) y[i]=axe*i-y[i];
		sort(y+1,y+m+1);
		mid=m+1>>1;
		for(int i=1;i<mid;i++) ans=ans+y[mid]-y[i];
		for(int i=mid+1;i<=m;i++) ans=ans+y[i]-y[mid];
	}
	if(ans)cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章