AcWing_105 七夕祭

七夕祭

题目链接

AcWing_105 七夕祭

题目描述

七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。

于是 T Y V J TYVJ TYVJ 今年举办了一次线下七夕祭。

V a n i Vani Vani 同学今年成功邀请到了 c l cl cl 同学陪他来共度七夕,于是他们决定去 T Y V J TYVJ TYVJ 七夕祭游玩。

T Y V J TYVJ TYVJ 七夕祭和 11 11 11 区的夏祭的形式很像。

矩形的祭典会场由 N N N M M M 列共计 N × M N×M N×M 个摊点组成。

虽然摊点种类繁多,不过 c l cl cl 只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。

V a n i Vani Vani 预先联系了七夕祭的负责人 z h q zhq zhq,希望能够通过恰当地布置会场,使得各行中 c l cl cl 感兴趣的摊点数一样多,并且各列中 cl 感兴趣的摊点数也一样多。

不过 z h q zhq zhq 告诉 V a n i Vani Vani,摊点已经随意布置完毕了,如果想满足 cl 的要求,唯一的调整方式就是交换两个相邻的摊点。

两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。

由于 z h q zhq zhq 率领的 T Y V J TYVJ TYVJ 开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。

现在 V a n i Vani Vani 想知道他的两个要求最多能满足多少个。

在此前提下,至少需要交换多少次摊点。

输入格式

第一行包含三个整数 N N N M M M T T T T T T 表示 cl 对多少个摊点感兴趣。

接下来 T T T 行,每行两个整数 x , y x,y x,y,表示 cl 对处在第 x x x 行第 y y y 列的摊点感兴趣。

输出格式

首先输出一个字符串。

如果能满足 V a n i Vani Vani 的全部两个要求,输出 b o t h both both

如果通过调整只能使得各行中 cl 感兴趣的摊点数一样多,输出 r o w row row

如果只能使各列中 c l cl cl 感兴趣的摊点数一样多,输出 c o l u m n column column

如果均不能满足,输出 i m p o s s i b l e impossible impossible

如果输出的字符串不是 i m p o s s i b l e impossible impossible, 接下来输出最小交换次数,与字符串之间用一个空格隔开。

数据范围

1 ≤ N , M ≤ 100000 , 0 ≤ T ≤ m i n ( N ∗ M , 100000 ) , 1 ≤ x ≤ N , 1 ≤ y ≤ M 1≤N,M≤100000,\\ 0≤T≤min(N∗M,100000),\\ 1≤x≤N,\\ 1≤y≤M 1N,M100000,0Tmin(NM,100000),1xN,1yM

输入样例:

2 3 4
1 3
2 1
2 2
2 3

输出样例:

row 1

思路

由于交换同一列相邻两行的摊位只会改变相关行的“感兴趣摊点数”,交换同一行相邻两列的摊位只会改变相关列的“感兴趣摊点数”,所以可以将问题分成“各列相邻两行的交换”和“各行相邻两列的交换”两部分来解。

以“各行相邻两列的交换”为例。

a i a_i ai 为每一列的“感兴趣摊点数”,其中 1 ≤ i ≤ m 1 \le i \le m 1im ,若问题有解,那么交换完成后,每个 a i ′ a'_i ai 一定都是相等的,即 t t t 可以被 m m m 整除。这样问题就变成了“均分纸牌”问题

最优的结果一定是只与右侧(或左侧)的摊位交换的。

x i x_i xi 为第 i i i 列与 第 i − 1 i-1 i1 列交换的次数(可以为负), a ˉ = i ∗ t m \bar{a}=i*\frac{t}{m} aˉ=imt,那么我们有:
x 1 = x 1 x 2 = a 2 + x 1 − a ˉ x 3 = a 3 + x 2 − a ˉ x 4 = a 4 + x 3 − a ˉ x i = a i + x i − 1 − a ˉ x_1=x_1\\ x_2=a_2+x_1-\bar{a}\\ x_3=a_3+x_2-\bar{a}\\ x_4=a_4+x_3-\bar{a}\\ x_i=a_i+x_{i-1}-\bar{a} x1=x1x2=a2+x1aˉx3=a3+x2aˉx4=a4+x3aˉxi=ai+xi1aˉ

如果把所有式子都用 x 1 x_1 x1 来表示,则有:
x 1 = x 1 − 0 x 2 = x 1 − ( a ˉ − a 2 ) x 3 = x 1 − ( 2 × a ˉ − a 2 − a 3 ) x 4 = x 1 − ( 3 × a ˉ − a 2 − a 3 − a 4 ) x i = x 1 − ( i × a ˉ − ∑ j = 1 i a i ) x_1=x_1-0\\ x_2=x_1-(\bar{a}-a_2)\\ x_3=x_1-(2 \times \bar{a}-a_2-a_3)\\ x_4=x_1-(3 \times \bar{a}-a_2-a_3-a_4)\\ x_i=x_1-(i\times \bar{a}-\sum_{j=1}^i a_i) x1=x10x2=x1(aˉa2)x3=x1(2×aˉa2a3)x4=x1(3×aˉa2a3a4)xi=x1(i×aˉj=1iai)

于是问题就变成了,求一个最优的 x k x_k xk,使得 ∑ i = 1 n ∣ x k − ( i × a ˉ − ∑ j = 1 i a i ) ∣ \sum_{i=1}^n |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)| i=1nxk(i×aˉj=1iai) 最小。这实际上就是“货仓选址”问题,其中 ∣ x k − ( i × a ˉ − ∑ j = 1 i a i ) ∣ |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)| xk(i×aˉj=1iai) 就相当于“货仓选址”问题中每个货仓的地址。很显然,只有 x k x_k xk 为所有 x i x_i xi 的中位数时,问题的答案才有最小值,详情请见。

由于: x k = ∑ i = 1 n ∣ x k − ( i × a ˉ − ∑ j = 1 i a i ) ∣ x_k=\sum_{i=1}^n |x_k-(i\times \bar{a}-\sum_{j=1}^i a_i)| xk=i=1nxk(i×aˉj=1iai)
所以答案的式子还可以表示成: ∑ i = 1 n ∣ ( i × a ˉ − ∑ j = 1 k a j ) − ( i × a ˉ − ∑ j = 1 i a i ) ∣ \sum_{i=1}^n |(i\times \bar{a}-\sum_{j=1}^k a_j)-(i\times \bar{a}-\sum_{j=1}^i a_i)| i=1n(i×aˉj=1kaj)(i×aˉj=1iai)

若设 s i = i × a ˉ − ∑ j = 1 i a i s_i=i\times \bar{a}-\sum_{j=1}^i a_i si=i×aˉj=1iai,那么最后答案的式子就变成了:
∑ i = 1 n ∣ s k − s i ∣ \sum_{i=1}^n |s_k-s_i| i=1nsksi

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
long long n,m,t,x,y;
long long row[100001],col[100001];
long long solve(long long a[100001],long long x)
{
	int f[100001],s[100001],ans,k;
	for(int i=1;i<=x;i++)
	{
		f[i]=a[i]-t/x;
		s[i]=s[i-1]+f[i];
	}
	sort(s+1,s+x+1);
	if(n&1)//求中位数 
		k=(x+1)/2;
	else
		k=x/2;
	ans=0;
	for(int i=1;i<=x;i++)
		ans+=abs(s[i]-s[k]);
	return ans;
}
int main()
{
	scanf("%lld%lld%lld",&n,&m,&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%lld%lld",&x,&y);
		row[x]++,col[y]++;
	}
	if(t%n==0&&t%m==0)
		printf("both %lld",solve(row,n)+solve(col,m));
	else if(t%m==0)
		printf("column %lld",solve(col,m));
	else if(t%n==0)
		printf("row %lld",solve(row,n));
	else
		printf("impossible");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值