标签:type namespace ace for class i+1 icp efi eof
网上想找篇这题的题解还挺费劲的...
首先看起来是博弈实则用dp来做,虽然用dp但还是有点博弈的感觉。首先对于一块巧克力,体力值大的人具有话语权,因为两个人轮流放弃的话,最后一定是体力少的被迫选那块巧克力,这个题中有关体力值的数据又都非常大,所以考虑两人体力值的差值。
我们用两个dp数组来体现两个人博弈的关系。\(FA[i][j]\)表示当前A在选第i个巧克力,想要选到第n个时A获得美味度为j,A需要与B体力值的最小差值(A表示第一个人,B表示第二个人)。\(FB[i][j]\)表示当前B在选第i个巧克力,想要选到第n个时A获得美味度为j,A需要与B体力值的最小差值。由于两人的竞争关系,A想要让FA尽可能小(不费吹灰之力),B想让FB尽可能大(让A难受)。同时有初始值\(FA[n+1][0]=FB[n+1][0]=-INF\)(表示体力值差多少都行)
第一个转移方程:
\(FA[i][j] = min(FB[i+1][max(j-s[i], 0LL)]-r[i], max(FA[i+1][j]+1+r[i], 1LL))\)
第一项表示假如A选择吃掉这块巧克力,值就等于轮到B选第n+1块巧克力时的状态(由于FA第二维表示i开始选到n要获得美味度j,吃了第i块获得s[i]那么第i+1块开始,只要吃够j-s[i]就行了,当然吃够就行了,所以j-s[i]不能小于0。因为会获得体力值r[i],所以目前状态就是下一个状态减去r[i])。第二项表示如果A没吃,B吃了,那么一方面A要损失1点体力值,同时B要增加体力值r[i],A目前的状态就会是\(FA[i+1][j]+1+r[i]\),当然这个值要大于1,不然他就没有不吃的资格。
第二个转移方程:
\(FB[i][j] = max(FA[i+1][j]+r[i], min(FA[i][j]-1, -1LL))\)
思路和第一个方程差不多,想明白还挺费劲的,max体现了B想让A尽可能费劲。
最后遍历一遍\(FA[1][j](sum >=j>=0)\), j从大到小遍历,如果FA的值小于A与B的差值,答案就是j
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
ll FA[200][200], FB[200][200];
ll r[200], s[200];
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int n, a, b;
int sum = 0;
cin >> n >> a >> b;
for(int i=1; i<=n; i++){
cin >> r[i] >> s[i];
sum += s[i];
}
memset(FA, 0x3f, sizeof(FA));
memset(FB, 0x3f, sizeof(FB));
FA[n+1][0] = -INF;
FB[n+1][0] = -INF;
for(int i=n; i>0; i--){
for(int j=0; j<=sum; j++){
FA[i][j] = min(FB[i+1][max(j-s[i], 0LL)]-r[i], max(FA[i+1][j]+1+r[i], 1LL));
FB[i][j] = max(FA[i+1][j]+r[i], min(FA[i][j]-1, -1LL));
}
}
int ans;
for(int i=sum; i>=0; i--){
if(FA[1][i]<=a-b){
ans = i;
break;
}
}
cout << ans << " " << sum-ans << endl;
return 0;
}
2014-2015 ACM-ICPC, Asia Tokyo Regional Contest-I Sweet War
标签:type namespace ace for class i+1 icp efi eof
原文地址:https://www.cnblogs.com/DinoMax/p/13861813.html