标签:gre min 前缀和 七夕 成功 lap for attr clu
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 }
标签:gre min 前缀和 七夕 成功 lap for attr clu
原文地址:https://www.cnblogs.com/iwannabe/p/10165024.html