题目大意:
现在Ciel和Jiro玩一个游戏
初始状态的时候桌子上面有n堆牌(1 <= n <= 100) 第i堆排有si (1 <= si <= 100) 张牌, 给出每张牌的值ck, (1 <= ck <= 1000)
Ciel先手, 每次可以选择一个非空的牌堆中拿走最上面的一张牌, Jiro后手每次选择一个非空的牌堆拿走最下面的一张牌, 两者都想使得自己得到的牌的和尽量大, 求在Ciel和Jiro都采取最优策略的情况下两者的分数
大致思路:
首先对于一个偶数张牌的堆, 当两者都采取最优策略的时候, Ciel会拿走上面的一半, 而Jiro会拿走下面的一半, 这是因为, Ciel在这样一堆牌中不能赢得更多, 每次Ciel选择这一堆牌时Jiro都可以在其拿下一张时, 拿到最下面的牌, 同样对于奇数堆来说上半部分会被Ciel获得, 下半部分被Jiro获得, 中间那张牌就成为竞争的对象, 在很多个奇数堆当中, 正中间那张牌将会成为竞争对象, 所以先手会抢得中间最大的牌, Jiro其次, Ciel再拿到第三大的牌, Jiro再其次...
所以要得到最优策略下两者的得分, 只需要对奇数堆中间的数排序即可
代码如下:
Result : Accepted Memory : 444 KB Time : 31 ms
/* * Author: Gatevin * Created Time: 2015/2/28 13:43:49 * File Name: Shana.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; int n; int s[110][1010]; int cnt[110]; vector <int> v; int main() { cin>>n; int ans1 = 0, ans2 = 0; for(int i = 1; i <= n; i++) { scanf("%d", &cnt[i]); for(int j = 1; j <= cnt[i]; j++) scanf("%d", &s[i][j]); if(cnt[i] & 1) { v.push_back(s[i][(cnt[i] + 1) >> 1]); for(int j = 1; j <= cnt[i] / 2; j++) ans1 += s[i][j]; for(int j = (cnt[i] + 1) / 2 + 1; j <= cnt[i]; j++) ans2 += s[i][j]; } else { for(int j = 1; j <= cnt[i] / 2; j++) ans1 += s[i][j]; for(int j = (cnt[i] / 2 ) + 1; j <= cnt[i]; j++) ans2 += s[i][j]; } } sort(v.begin(), v.end(), greater<int>()); for(unsigned int i = 0; i < v.size(); i++) { if(i & 1) ans2 += v[i]; else ans1 += v[i]; } cout<<ans1<<" "<<ans2<<endl; return 0; }