1. 程式人生 > >七夕祭(貪心+分金幣問題)

七夕祭(貪心+分金幣問題)

問題 M: 七夕祭

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 75  解決: 20
[提交] [狀態] [討論版] [命題人:admin]

題目描述

七夕節因牛郎織女的傳說而被扣上了「情人節」的帽子。於是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。

分析:這個題是均分紙牌,分金幣的升級版。下面以分金幣問題引入。

一、分金幣:

1、題意:圓桌旁坐著n個人,每人有一定數量的金幣,金幣總數總能被n整除。每個人可以給他左右相鄰的人一些金幣,最終使得每個人的金幣數相等,你的任務是求出被轉手的金幣數量的最小值。

2、已知每個人初始情況下手中的金幣數,那麼總金幣數MZ=X1+X2+X3+....+XN。最終每個人獲得的金幣就是M=MZ/N。

3、設整個交換過程中第n個人給第n-1個人共An枚金幣,

對於n=1時為第一人給第n個人金幣數。

4、可得

x1-A1+A2=M; => A1=x1+A2-M;

x2-A2+A3=M; => A2=x2+A3-M;

x3-A3+A4=M; => A3=x3+A4-M;

x4-A4+A1=M; => A4=x4+A1-M;

5、X2=X1-(M-A1);

     X3=X2-(M-A2);

     X4=X3-(M-A3);

     X5=X4-(M-A4);

6、設

           x2=x1-C1;

           x3=x1-C2;

           x4=X1-C3;

           被轉手的金幣數量:ans=|x1|+|x2|+|x3|+|x4|........+|xn|=|x1-0|+|x1-C1|+|x1-C2|.....+|x1-Cn-1|。

(看不懂的,可以從4開始自己往6推一下)

7、問題就是就一個ans的最小值,就可以看作,一共n個點,找到一個點到其它各個點的距離之和最小,經典的貨倉選址問題。

X1為C陣列的中位數時ans最小。到這裡就搞定了。

二、七夕祭

1、impossible的情況很簡單,就是行數、列數都不是T的因數。

2、對於行和列互不影響,分開求,就是兩個分金幣問題。

3、如果n是T的因數,m也是T的因數,那麼就是both。

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#define INF 0x3f3f3f3f
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e5+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
int n,m,t;
int row[MAX],col[MAX];
ll ans;
void solve_row()
{
    ll b[MAX],ave=0,mid;
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++)
        ave+=row[i];
    ave/=n;
    for(int i=1;i<=n;i++)
        row[i]-=ave;

    for(int i=1;i<=n;i++)
        b[i]=b[i-1]+row[i];
    sort(b+1,b+1+n);
    mid=b[(n+1)/2];

    for(int i=1;i<=n;i++)
        ans+=abs(b[i]-mid);
}
void solve_col()
{
    ll b[MAX],ave=0,mid;
    memset(b,0,sizeof(b));
    for(int i=1;i<=m;i++)
        ave+=col[i];
    ave/=m;
    for(int i=1;i<=m;i++)
        col[i]-=ave;

    for(int i=1;i<=m;i++)
        b[i]=b[i-1]+col[i];
    sort(b+1,b+1+m);
    mid=b[(m+1)/2];

    for(int i=1;i<=m;i++)
        ans+=abs(b[i]-mid);
}
int main()
{
    scanf("%d%d%d",&n,&m,&t);
    for(int i=1;i<=t;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        row[x]++;
        col[y]++;
    }

    if(t%n && t%m)
    {
        printf("impossible\n");
        return 0;
    }
    if(t<n && t<m)
    {
        printf("impossible\n");
        return 0;
    }
    if(t%n==0)
        solve_row();
    if(t%m==0)
        solve_col();

    if(t%m==0 && t%n==0) printf("both %lld\n",ans);
    else if(t%n==0) printf("row %lld\n",ans);
    else if(t%m==0) printf("column %lld\n",ans);
    return 0;
}