【codevs2485】七夕祭(貪心,環形紙牌均分)

小哈里發表於2018-05-15

solution

1、首先行列獨立互相不影響,可以單獨統計。於是就變成了一個環形紙牌均分問題。
2、紙牌均分問題每行答案是i=1n|iT/nG[i]|

\sum_{i=1}^n|i*T/n-G[i]|
,其中T為總牌數,G[i]是a[i]的字首和,a[i]為每個人的牌數。(這裡考慮讓每個人一開始手中的牌數都減去T/n
T/n
(為什麼要減,後面就有好處了),答案顯然不變(數學上也可以推匯出),每行答案即為i=1nS[i]
\sum_{i=1}^nS[i]
,其中s[i]為b[i]字首和,b[i]=a[i]-T/n。)
3、對於環,可以拆為鏈,但是複雜度會上升。考慮從第k個人斷開,寫成一行,這n個人持有的紙牌數字首和分別為(a[k+1],s[k+1]-s[k]; a[k+2],s[k+2]-s[k];a[n],s[n]-s[k];a[1],s[1]+s[n]-s[k]);因為s[n]=0(前面已經減去了t/n,所以均分後每個人手中有0張牌)。所以答案就是i=1n|s[i]s[k]|
\sum_{i=1}^n|s[i]-s[k]|
,這裡可以列舉k得到最小值(那為什麼還要這麼麻煩的用在上面減去T/n呢,難道是為了公式好看?)不。。。也可以直接統計,因為,——到這裡就是一個貨倉選址問題。

codes

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int n, m, t;
int b[maxn], c[maxn], s[maxn];
long long calc(int a[], int n){
    for(int i = 1; i <= n; i++){
        a[i] -= a[0]/n;
        s[i] = s[i-1]+a[i];
    }
    sort(s+1,s+n+1);
    int ans = 0;
    for(int i = 1; i <= n; i++)ans += abs(s[i]-s[n+1>>1]);
    return ans;
}

int main(){
    cin>>n>>m>>t;
    for(int i = 1; i <= t; i++){
        int x, y;  cin>>x>>y;
        b[x]++, c[y]++;
    }
    for(int i = 1; i <= n; i++)b[0]+=b[i];
    for(int i = 1; i <= m; i++)c[0]+=c[i];
    if(b[0]%n==0 && c[0]%m==0)
        cout<<"both "<<calc(b,n)+calc(c,m)<<"\n";
    else if(b[0]%n==0)
        cout<<"row "<<calc(b,n)<<"\n";
    else if(c[0]%m==0)
        cout<<"column "<<calc(c,m)<<"\n";
    else cout<<"impossible\n";
    return 0;
}

相關文章