习题:七夕祭(杂题)

题目

思路

首先一点如果是impossible,那么一定

\(T\%N\)\(T\%M\)都不为0

再接着,

因为竖着满足跟横着满足本质上是一样的,所以这里只讨论横着满足

并且如果要满足横着的情况,

如果要步数最小,那么我们一定不会将竖着的摊位交换

同理,如果要满足竖着的情况,我们一定不会将横着的摊位交换

也就是说如果我们定义两个数组row和col来维护每一行和每一列的摊位个数

那么竖着交换对col数组没有任何影响,横着交换对row数组也没有任何影响

也就是指,如果是both的话,

我们只需要将横着交换的最小值和竖着交换的最小值相加即可

因为我们只需要横着满足,所以我们其实并不在意整个矩阵长成什么样子

我们所需要知道的,只是每一横着有多少个摊点

问题转换为:

现在我们有一个环,我们只能使相邻的元素一个+1,一个-1,求最小的步数使这个数列的元素变为一样

然后?

这个模型你们不熟悉?

如果真不熟悉的话,

蒟蒻笔者还是解释一下

t就是题意中的t

我们先对于每一个元素求出他到指定元素的差距,即\(row_i=row_i-t/n\)

接着求出前缀和数组\(srow\),然后求出对\(srow\)排序之后的中点\(mid=srow_{(n+1)/2}\),n+1是防止精度

最后\(ans=\sum_{i=1}^{n}abs(srow_i-mid)\)

你可以用方程思想去理解

我们设原本每一个元素为\(a_i\)

第i个元素向第i-1个元素的贡献为\(x_i\)

一定有方程

\(\frac{t}{n}=a_i-x_i+x_{i+1}\)

这样还看不出什么来

但是如果你用主元的思想

我们再设\(c_j=\sum_{i=1}^{j}a_i-j*\frac{t}{n}\)

\(\frac{t}{n}=a_i-x_i+x_{i+1}\)

\(\begin{aligned}x_2&=\frac{t}{n}-a_1+x_1\\&=x_1-c_1\end{aligned}\)

同理

\(\begin{aligned}x_3&=\frac{t}{n}-a_2+x_2\\&=\frac{t}{n}-a_2+x_1-c_1\\&=\frac{t}{n}-a_2+x_1+\frac{t}{n}-a_1\\&=x_1-c_2\end{aligned}\)

之后

\(x_i=x_1-c_i\)

答案是什么?

\(\begin{aligned}ans&=\sum_{i=1}^{n}x_i\\&=\sum_{i=1}^{n}|x_1-c_i|\end{aligned}\)

之后?

\(c_i\)已知,也就是说ans只和\(x_1\)有关

并且我们要求最小值,

之后,\(x_1\) 不就是数组\(c\)的中位数?

代码

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
struct node
{
	int x,y;
}a[200005];
int n,m,t;
int col[200005];
int row[200005];
int s_row[200005];
int s_col[200005];
int ans_row;
int ans_col;
int f_abs(int x)
{
	if(x<0)
		return -x;
	return x;
}
signed main()
{
	cin>>n>>m>>t;
	if(t%n!=0&&t%m!=0)
	{
		cout<<"impossible";
		return 0;
	}
	for(int i=1;i<=t;i++)
	{
		cin>>a[i].x>>a[i].y;
		row[a[i].x]++;
		col[a[i].y]++;
	}
	if(t%n==0)
	{
		for(int i=1;i<=n;i++)
			row[i]=row[i]-t/n;
		for(int i=1;i<=n;i++)
			s_row[i]=s_row[i-1]+row[i];
		sort(s_row+1,s_row+1+n);
		int mid=s_row[(n+1)/2];
		for(int i=1;i<=n;i++)
			ans_row+=f_abs(mid-s_row[i]);
	}
	if(t%m==0)
	{
		for(int i=1;i<=m;i++)
			col[i]=col[i]-t/m;
		for(int i=1;i<=m;i++)
			s_col[i]=s_col[i-1]+col[i];
		sort(s_col+1,s_col+1+m);
		int mid=s_col[(m+1)/2];
		for(int i=1;i<=m;i++)
			ans_col+=f_abs(mid-s_col[i]);
	}
	if(t%n==0&&t%m==0)
	{
		cout<<"both "<<ans_row+ans_col;
		return 0;
	}
	if(t%n==0)
	{
		cout<<"row "<<ans_row;
		return 0;
	}
	if(t%m==0)
	{
		cout<<"column "<<ans_col;
		return 0;
	}
	return 0;
}

posted @ 2020-01-11 11:37  loney_s  阅读(233)  评论(3)    收藏  举报