题目大意:
就是现在n个海盗分配m枚金币, 依次编号为P1~Pn
然后海盗按照Pn->P(n - 1)->...->P2->P1的顺序提出分配方案, 然后或者的海盗投票表示是否赞成这个方案, 提出方案的海盗也会参与投票, 如果有一半或者以上的海盗赞成, 那么这个方案就通过, 按照这个方案分配金币, 否则这个海盗会被扔进海里喂鲨鱼, 各个海盗都决定聪明并且想使得自己的利益最大化, 当然这里各个海盗首先要能够存活才会考虑使得自己的金币尽量多, 问P(p)编号的海盗最后会获得多少个金币(当有多个可能时输出最少的)
大致思路:
首先当m个海盗按照经典的海盗分金问题进行分配的时候, 如果m个金币够分, 也就是说n <= 2*m的时候, 不会有什么问题, 第n个海盗分得最多的钱, 和Pn间隔为偶数的获得1金币, 其他0金币
那么整个问题变复杂的地方出现在当m个金币不够分的情况也就是当n > 2*m的时候
当n == 2*m + 1的时候, 第n个人只有将所有m个金币分给2*m个人的情形下没有金币的m个人, 每人一金币, 才能活命, 否则某个海盗在让第n个人死的情形下自己的利益没有变化, 那么n的方案就会被反对, 那样反对票回避支持多一票, Pn就死了, 所以Pn为了活命只能给所有Pi(i是奇数)的人分1金币保证自己不死
当n == 2*m + 2的时候, Pn需要把自己的m个金币分给在n == 2*m + 1情形下没有金币的人, 才能加上自己的票保证不死, 那么n == 2*m + 1情形下有m + 1个人没有金币, 也就是说, m个金币给这些人的时候这m + 1个人也都是有可能没有金币的, 所以询问n == 2*m + 2清醒下的每一个人答案都是0
当n == 2*m + 3时, Pn最多将m个金币分给n == 2*m + 2情形下一定拿不到金币的m个人, 那么加上自己一票也只有m + 1票, 提出方案的人一定会死, 其他人就遵循n == 2*m + 2的金币分配作为答案了
当n == 2*m + 4时, P(n - 1)为了活命无论什么分配方案都会支持, 因为到他提方案自己一定会死, 所以此时Pn将金币分给上个n的情形中拿不到金币不会死的m个人(当然满足条件的人不止m个, 所以询问这些人时答案还是0), 加上自己的赞成票, 一共m + 2票通过, Pn在这个情形下不死
n == 2*m + 5时Pn死亡, n == 2*m + 6时Pn死亡, n == 2*m + 7时Pn死亡, n == 2*m + 8时Pn可以保命, 因为前三个一定要支持他, 不然都会死, 那么加上m票和自己的票一定半数通过
于是可以发现, 只有当n == 2*m + 2^i的时候Pn能保命, 否则就死亡
于是这个题目也就做出来了...
代码如下:
Result : Accepted Memory : 1584 KB Time : 15 ms
/* * Author: Gatevin * Created Time: 2015/5/13 11:04:52 * File Name: Rin_Tohsaka.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e) #define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl int n, m, p; int main() { int t; scanf("%d", &t); while(t--) { scanf("%d %d %d", &n, &m, &p); if(n > 2*m) { if(n == 2*m + 1) { if(p == n) puts("0"); else if(p & 1) puts("1"); else puts("0"); continue; } if(__builtin_popcount(n - 2*m) == 1)//是n == 2*m + 2^i的状况 { puts("0"); continue; } n -= 2*m; int cnt = 30; while(((1 << cnt) & n) == 0) cnt--; n = (1 << cnt); if(p -2*m <= n) puts("0"); else puts("Thrown"); continue; } if(p == n) printf("%d\n", m - (n - 1) / 2); else if((n - p) & 1) puts("0"); else puts("1"); } return 0; }