:七夕祭 (货仓选址+均分纸牌)

问题 : 七夕祭

时间限制: 1 Sec  内存限制: 128 MB

题目描述

七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。于是TYVJ今年举办了一次线下七夕祭。Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩。
TYVJ七夕祭和11区的夏祭的形式很像。矩形的祭典会场由N排M列共计N×M个摊点组成。虽然摊点种类繁多,不过cl只对其中的一部分摊点感兴趣,比如章鱼烧、苹果糖、棉花糖、射的屋……什么的。Vani预先联系了七夕祭的负责人zhq,希望能够通过恰当地布置会场,使得各行中cl感兴趣的摊点数一样多,并且各列中cl感兴趣的摊点数也一样多。不过zhq告诉Vani,摊点已经布置完毕了,唯一的调整方式就是交换两个相邻的摊点。两个摊点相邻,当且仅当他们处在同一行或者同一列的相邻位置上。由于zhq率领的TYVJ开发小组成功地扭曲了空间,每一行或每一列的第一个位置和最后一个位置也算作相邻。现在Vani想知道他的两个要求最多能满足多少个。在此前提下,至少需要交换多少次摊点。

输入

第一行包含三个整数N和M和T。T表示cl对多少个摊点感兴趣。
接下来T行,每行两个整数x,y,表示cl对处在第x行第y列的摊点感兴趣。

输出

首先输出一个字符串。如果能满足 Vani 的全部两个要求,输出 both;如果通过调整 只能使得各行中 cl 感兴趣的摊点数一样多,输出 row;如果只能使各列中 cl 感兴趣的摊点 数一样多,输出 column;如果均不能满足,输出 impossible。
如果输出的字符串不是 impossible, 接下来输出最小交换次数,与字符串之间用一 个空格隔开。

样例输入

2 3 4
1 3
2 1
2 2
2 3

样例输出

row 1

提示

对于30%的数据,N,M≤100。
对于70%的数据,N,M≤1000。
对于100%的数据,1≤N,M≤100000,0≤T≤min(NM,100000),1≤x≤N,1≤y≤M。

题意:通过最小的次数交换,使得每行每列上cl感兴趣的摊点数相同。

思路:因为摊点进行行交互并不影响列上的情况,进行列交换也不影响行上的情况,所以我们可以分别进行     --------      1、行交换     2、列交换

① 我们很容易知道如果要进行行交换(列),t%n(m) == 0,否则是无法平均分配的

②如果首尾不相连(无法交换),我们知道这是一个均分纸牌问题 ans =   Σ(|  i*(t/n)- G【i】 |)(G【i】是牌数C【i】的前缀和),可以理解为当前拥有G【i】张牌,规定拥有i*(t/n)张,当前需要移动次数就是| i*(t/n)-G【i】|,令A【i】 = C【i】-t/n,S【i】为A【i】的前缀和,ans = |S【i】|

③如果首尾相连(可以交换),那就变成了一个环形的均分纸牌,但是我们可以知道,最有的方案肯定存在一个相邻的位置没有进行交换,将其拆开,分成一条链,又变成了均分纸牌问题

(假设 n 个位置,总共n-1对相邻关系,如果进行了n-2次交换,使得n-1个位置平衡,那么第n个位置也肯定平衡了,就不必交换)

④那么我们需要枚举拆开的位置 j, ans += S【j+i】-S【j】   (j+i <= n)

                ans+= S【n】+S【j+i-n】-S【j】    ( i + j > n)

因为S【n】是前面所有A【i】的前缀和,S【n】 ==  0  (S【n】 ==  G【n】- t)

所以ans  = Σ( |  S【i】-S【k】|),这就是一个货仓选址问题

⑤我们将 S 排序,知道如果 

            n为奇数,ans = sum(| S【i】- S【(n+1)/2】|)

            n为偶数,ans = sum(| S【i】- S【n/2】|)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,t;
 4 typedef long long ll;
 5 const int maxn = 1e5+5;
 6 ll row[maxn];
 7 ll col[maxn];
 8 
 9 int solve(ll *Ar,int type)
10 {
11     int len,avr;
12     if(type == 0)len = n,avr = t/n;
13     else len = m,avr = t/m;
14     for(int i=1;i<=len;i++)Ar[i] += Ar[i-1]-avr;
15     ll ans = 0;
16     sort(Ar+1,Ar+1+len);
17     int tmp;
18     if(len & 1)tmp = Ar[(len+1)/2];
19     else tmp = Ar[(len/2)];
20     for(int i=1;i<=len;i++)ans += abs(Ar[i]-tmp);
21     return ans;
22 }
23 
24 int main()
25 {
26     scanf("%d%d%d",&n,&m,&t);
27     for(int i=1;i<=t;i++)
28     {
29         int x,y;
30         scanf("%d%d",&x,&y);
31         row[x]++;
32         col[y]++;
33     }
34 
35     if(t%n == 0 && t% m == 0)
36     {
37         printf("both ");
38         printf("%lld
",solve(row,0)+solve(col,1));
39     }
40     else if(t % n == 0)
41     {
42         printf("row ");
43         printf("%lld
",solve(row,0));
44     }
45     else if(t % m == 0)
46     {
47         printf("column ");
48         printf("%lld
",solve(col,1));
49 
50     }
51     else printf("impossible
");
52 }
View Code
原文地址:https://www.cnblogs.com/iwannabe/p/10165024.html