A
和B
在玩游戏。他们面前有一个数组。他们只能拿最左边或最右边的数,然后加进他们的得分,得分越大越好。他们都会以最优的方法拿,求最后的分数差。(感谢rxz老师
的翻译)
记 表示先手在区间 内的得分, 表示后手在区间 内的得分, 表示第 个数, 表示区间 内数的总和。所以,我们有:
我来解释一下它们的含义:第一条转移式比较难理解,为什么前面是 而后面就成了 了呢?不是同一个人吗?其实不然, 和 的定义并不是针对某个人的,仅仅是先手后手。什么意思?就是任何一个人都可以调用 或 来求出自己的得分。
那第一条转移式是什么意思呢?就是说,
即先手取了第
个数,然后A
和·B
就只能在区间
中取数,而因为轮到其它人选了,所以在区间
中他是后手,所以是
。
类似。
的转移比较简单,因为后手没有什么自动权,所以他的得分就是区间得分总和 先手的得分。
于是,我们用一个递归 两函数互相调用就可以求出答案。答案即 。
int a[1010][1010],test_number,n;
int b[1010][1010],pre[1010],w[1010];
bool va[1010][1010],vb[1010][1010];
inline void init_the_array(){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(w,0,sizeof(w));
memset(pre,0,sizeof(pre));
memset(va,false,sizeof(va));
memset(vb,false,sizeof(vb));
}//初始化数组
inline void read_the_data(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
pre[i]=pre[i-1]+w[i];
}
}//读入数据以求解
inline int sum(int l,int r){
return pre[r]-pre[l-1];
}//利用前缀和O(1)求[l,r]的分数和
inline int A(int l,int r);
inline int B(int l,int r);
inline int A(int l,int r){
if (l==r) return w[l];
if (va[l][r]) return a[l][r];
a[l][r]=max(w[l]+B(l+1,r),w[r]+B(l,r-1));
va[l][r]=true;return a[l][r];
}//计算先手在区间[l,r]内的得分
inline int B(int l,int r){
if (vb[l][r]) return b[l][r];
b[l][r]=sum(l,r)-A(l,r);
vb[l][r]=true;return b[l][r];
}//计算后手在区间[l,r]内的得分
inline void calc_the_answer(){
init_the_array();
read_the_data();
printf("%d\n",A(1,n)-B(1,n));
}
int main(){
scanf("%d",&test_number);
while (test_number--)
calc_the_answer();
return 0;
}
*****************************
语言:C++
状态:Accepted
得分:100分
备注:无头文件和快读read()函数
*****************************
我们有一个剑客,需要给对手 点伤害。他每 秒可以给 点伤害。有 种技能,需要 个金币,可把间隔 改为 (他最多只能学 种技能)。
除此之外,现场有 个群众,他需要 个金币,可以给出 点伤害(剑客只能雇 个群众)。
求剑客最少要多少时间杀死对手。
若有两个群众a
和b
,若a
需要的金币比b
少,且a
的伤害比b
多,那么我们把b
删去(因为a
比他更物美价廉),剩下的群众满足需要金币越多,伤害越大。
枚举学哪个技能,剩下的钱记为 。二分群众中需要的金币小于等于 且最大的群众(他在可以雇佣的前提下,伤害最大),我们在学习一次技能的前提下,雇佣他。
于是,我们可以枚举我们学习哪个技能,然后通过二分计算我们可以雇佣哪个群众,然后计算去最优值。
注意,可以不学技能,这样可能也最优(毕竟没花钱)!!!当然,也可以不选群众。
题目就做完了……
typedef long long ll;
const int N=1e5+100;
struct hero_id{
ll c,d;
bool operator < (hero_id p) const{
return d<p.d;
}
hero_id(ll _c=0,ll _d=0){c=_c;d=_d;}
}h[N];ll a[N],b[N];
vector<hero_id> chose;
ll n,m,k,x,s,ans;
void read_the_data(){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(h,0,sizeof(h));
chose.clear();//int i;
n=read();m=read();k=read();
x=read();s=read();
for(int i=1;i<=m;i++)
a[i]=read();
for(int i=1;i<=m;i++)
b[i]=read();
for(int i=1;i<=k;i++)
h[i].c=read();
for(int i=1;i<=k;i++)
h[i].d=read();
}
void choose_heros(){
sort(h+1,h+k+1);
chose.push_back(hero_id(0,0));
register ll maxn=0ll;
for(int i=1;i<=k;i++){
if (h[i].c<=maxn) continue;
chose.push_back(h[i]);maxn=h[i].c;
}
}
inline ll Left(ll p){
return (*(--upper_bound(chose.begin(),chose.end(),hero_id(0,p)))).c;
}
inline void calc_answer(){
ans=9e18;a[0]=x;b[0]=0;
for(int i=0;i<=m;i++)
if (s>=b[i]){
ll used=Left(s-b[i]),cost;
if (n-used<=0) cost=0ll;
else cost=(n-used)*a[i];
ans=min(ans,cost);
}
}
int test_number;
int main(){
test_number=read();
while (test_number--){
read_the_data();
choose_heros();
calc_answer();
printf("%lld\n",ans);
}
return 0;
}
*****************************
语言:C++
状态:Accepted
得分:100分
备注:无头文件和快读read()函数
*****************************