【算法进阶0x00】七夕祭

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/88931591

【题面】
            \;\;\;\;\;\, 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;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/88931591