:七夕祭 (貨倉選址+均分紙牌)
問題 : 七夕祭
時間限制: 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 = sum(| 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 = sum( | 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\n",solve(row,0)+solve(col,1)); 39 } 40 else if(t % n == 0) 41 { 42 printf("row "); 43 printf("%lld\n",solve(row,0)); 44 } 45 else if(t % m == 0) 46 { 47 printf("column "); 48 printf("%lld\n",solve(col,1)); 49 50 } 51 else printf("impossible\n"); 52 }View Code