D. Small srf game (reverse thinking + game + dp monotonic queue/line segment tree optimization)

https://blog.csdn.net/zstuyyyyccccbbbb/article/details/112912657 (Attach a similar question first)


Idea: Observing the sample, the answer to srf and qtc is to take a negative sign. So consider the score obtained when the srf first moves-the maximum value of the qtc score.

Why take the minus sign? For example:

2 2

1 2

srf is the first to take the 2 best, so qtc won't have to be taken. So the first answer is 2

Qtc first, the question actually means that you want to consider the maximum score obtained by qtc-srf first. Similarly, at this time, consider qtc as srf, and 2 is the best. The score is 2. The final question says no matter what if, output the score of srf-qtc, so take a negative number.

So here we simply consider the situation of srf first.

First of all, after srf takes the position of i, qtc can take a number from i+1 to i+m, but if it is swiping, it will affect the subsequent state of srf.

Up to this point, this topic has inspired us: if the current state is collision, then come backward. And it is very likely a dp-like transfer.

Here you can take a look at the problem of the beacon tower yesterday, imitating the design. From back to front, dp[i] indicates that srf takes the number i. At this time, [i~n] obtains the maximum value of srf first-qtc score.

Consider transfer: dp[i]=a[i]-max(dp[i+1~i+m]);

This transfer has its own way. The equation design of some group friends is different, and the transfer is also different. Then I fainted all night and did this problem according to my own ideas in the morning. If you don’t understand, you can refer to the blogs of other group friends.

(https://blog.csdn.net/weixin_45948940/article/details/112934074?utm_source=app&app_version=4.5.0

https://blog.csdn.net/tlyzxc/article/details/112976251

This transfer is like this. srf takes i. Because of the game, that is, the opponent is an Alpha Dog, he will find the maximum value that he can obtain to make the answer as small as possible. In [i+1~i+m], the dog is the first mover. He takes the maximum state, which is the state of the srf that has been updated before, and picks the largest one to make the score smaller. (Gaming)

Finally, here is a dp that needs to find the best value. I am not very familiar with monotonous queues, so I went to the line segment tree. (The optimization of monotonic queue can refer to the cluster above)

(The note is the naive equation)

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL dp[maxn],a[maxn];
struct Tree{
    LL l,r,maxval,tag;///区间最大值
}tree[maxn*4];
void push_up(LL p)
{
    tree[p].maxval=max(tree[p*2].maxval,tree[p*2+1].maxval);
}
void addtag(LL p,LL d)
{
    tree[p].tag=d;
    tree[p].maxval=tree[p].tag;
}
void push_down(LL p)
{
    if(tree[p].tag!=-1){
        addtag(p*2,tree[p].tag);
        addtag(p*2+1,tree[p].tag);
        tree[p].tag=-1;
    }
}
void build(LL p,LL l,LL r)
{
    tree[p].l=l;tree[p].r=r;tree[p].maxval=0;
    tree[p].tag=-1;
    if(l==r) {tree[p].maxval=0;return;}
    LL mid=(l+r)>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    push_up(p);
}
void modify(LL p,LL l,LL r,LL d)
{
    if(l<=tree[p].l&&r>=tree[p].r)///要修改的区间涵盖在区间内部
    {
            addtag(p,d);
            return;
    }
    push_down(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(l<=mid) modify(p*2,l,r,d);
    if(r>mid) modify(p*2+1,l,r,d);
    push_up(p);
}
LL query(LL p,LL l,LL r)
{
    if(l<=tree[p].l&&r>=tree[p].r)
    {
        return tree[p].maxval;
    }
    LL ans=-1e18;
    push_down(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(l<=mid) ans=max(ans,query(p*2,l,r));
    if(r>mid) ans=max(ans,query(p*2+1,l,r));
    return ans;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  build(1,1,n);
  for(LL i=1;i<=n;i++) cin>>a[i];
  for(LL i=1;i<=max(m,n)+10;i++) dp[i]=-1e18;
  dp[n]=a[n];  
  modify(1,n,n,a[n]);
  for(LL i=n-1;i>=1;i--){
    LL temp=-1e18;
    temp=max(temp,query(1,i+1,min(i+m,n)));
   // for(LL j=i+1;j<=min(i+m,n);j++){
   //     temp=max(dp[j],temp);
   // }
    dp[i]=a[i]-temp;
    modify(1,i,i,dp[i]);
  }
  LL ans=-0x3f3f3f3f;
  for(LL i=1;i<=m;i++){
    ans=max(ans,dp[i]);
  }
  cout<<ans<<endl<<-ans<<endl;
return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/112981622