【博弈】2012 world final L.Takeover Wars

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=547&page=show_problem&problem=4048

       又是我最喜欢的博弈,感觉非常难。。但是最后还是给我切掉了^_^!

       两个集团在进行收购战争,每次每个集团可以采用两种收购操作,

        1.用自己的子公司a收购自己另外的子公司b,完成之后b公司消失,a公司价值变成val[a]+val[b],

        2.用自己的子公司a收购对方的子公司c,必须满足val[a]>val[c],完成之后c公司小时,a公司价值不变

双方轮流操作,直到某一方没有子公司存在则输。

      详细证明我画了几张a4纸,就不搬上来,讲一下几个关键的结论,及其推导方向。

        1.集团内部的收购必然是最大的子公司与次大的子公司之间进行。显然这样具备其他两个子公司合并所能拥有的所有好处。

        2.集团间的收购,必然是针对对方最大的子公司。直观上可以这样想,如果你可以收购对方最大公司,你不可能去收购对方其他的公司;否则,你收购完了对方的b公司,对方将收购掉你当前最大子公司a。。由于val[a]>val[b],这样的交换对你是不利的。。当然很容易举出交换之后你还可以获胜的反例,但是可以证明这些例子执行合并操作也将获胜,故排除掉收购对方最大子公司之外的恶意收购。

        3.某个集团开始内部合并的时候,另外的集团也只能执行内部合并,直到某个集团新合并出来的最大的子公司,已经比对方当前最大的子公司小,此时胜负已经分晓,因为对方可以不停收购掉你新合并出来的公司,而使得你永远无法消灭他当前最大的子公司。。这个的证明必需依赖于2,当对方执行操作1之后,对于我方只有两种可能A可以收购对面新合并出来的子公司,此时获胜游戏结束,B不能,故由2可以得知此时我方也只能执行内部收购。

 有了这3点就可以很快解决问题了,此时可以将分成两种情况A.第一个集团一开始就先执行内部收购;B.第一个集团先执行恶意收购。之后根据1,2,3,有无论哪种情况第二个集团只能执行内部收购,直到胜负分晓。。。故整个题目只有一次决策,总复杂度为排序+O(n);

View Code
//By Lin
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<queue>

#define sqr(x) ((x)*(x))
#define Rep(i,n) for(int i = 0; i<n; i++)
#define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
#define X first
#define Y second
#define mp(x,y) make_pair(x,y)

using namespace std;
typedef long long LL;
typedef pair<int,int> pii;

#define N 100010
LL        data[2][N];
int        n[2];

bool    solve(){
    LL    a = data[0][0], b = data[1][0];
    for(int i = 1; i<=max(n[0],n[1]); i++){
        a += data[0][i];
        if ( a < b ) break;
        b += data[1][i];
        if ( a > b ) return true;
    }
    if ( data[0][0] < data[1][0] ) return false;
    a = data[0][0], b = data[1][1];
    for(int i = 2; i<=max(n[0],n[1]); i++){
        b += data[1][i];
        if ( b < a ) return true;
        a += data[0][i-1];
        if ( a < b ) return false;
    }
    return false;
}

int        main(){
    int    tt = 0;
    while ( ~scanf("%d%d", &n[0], &n[1] ) ){
        memset( data , 0 , sizeof(data) );
        Rep(k,2) {
            Rep(i,n[k]) scanf("%lld", &data[k][i] );
            sort( data[k] , data[k]+n[k] );
            reverse( data[k] , data[k]+n[k] );
        }
        printf("Case %d: %s\n" , ++tt , solve()?"Takeover Incorporated":"Buyout Limited" );
    }
    return 0;
}

 

posted @ 2013-03-13 17:01  lzqxh  阅读(336)  评论(0编辑  收藏  举报