D. Pequeno jogo srf (pensamento reverso + jogo + fila monotônica dp / otimização da árvore de segmento de linha)

https://blog.csdn.net/zstuyyyyccccbbbb/article/details/112912657 (Anexe uma pergunta semelhante primeiro)


Idéia: Observando a amostra, a resposta para srf e qtc é pegar um sinal negativo. Portanto, considere a pontuação obtida quando o srf se move pela primeira vez - o valor máximo da pontuação qtc.

Por que usar o sinal de menos? Por exemplo:

2 2

1 2

srf é o primeiro a pegar os 2 melhores, então qtc não precisa ser levado. Portanto, a primeira resposta é 2

Qtc primeiro, a questão realmente significa que você deseja considerar a pontuação máxima obtida por qtc-srf primeiro. Da mesma forma, neste momento, considere qtc como srf, e 2 é o melhor. A pontuação é 2. A pergunta final diz que não importa o que aconteça, imprima a pontuação de srf-qtc, então pegue um número negativo.

Portanto, aqui simplesmente consideramos a situação de srf primeiro.

Em primeiro lugar, depois que srf assume a posição de i, qtc pode assumir um número de i + 1 a i + m, mas se estiver passando, afetará o estado subsequente de srf.

Até este ponto, este tópico nos inspirou: se o estado atual é colisão, então volte para trás. E é muito provável que seja uma transferência semelhante a dp.

Aqui você pode dar uma olhada no problema da torre do farol de ontem, imitando o design. De trás para a frente, dp [i] indica que srf leva o número i. Nesse momento, [i ~ n] obtém o valor máximo da pontuação srf first-qtc.

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

Essa transferência tem seu próprio caminho. O desenho da equação de alguns amigos do grupo é diferente, e a transferência também é diferente. Então, desmaiei a noite toda e resolvi esse problema de acordo com minhas próprias idéias pela manhã. Se você não entende, pode consultar os blogs de outros amigos do grupo.

( 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

Esta transferência é assim. srf leva 1. Por causa do jogo, ou seja, o oponente é um Alpha Dog, ele encontrará o valor máximo que pode obter para tornar a resposta o menor possível. Em [i + 1 ~ i + m], o cão é o primeiro a se mover. Ele pega o estado máximo, que é o estado do srf que foi atualizado antes, e escolhe o maior para diminuir a pontuação. (Jogos)

Finalmente, aqui está um dp que precisa encontrar o melhor valor. Não estou muito familiarizado com filas monótonas, então fui para a árvore de segmento de linha. (A otimização da fila monotônica pode se referir ao cluster acima)

(A nota é a equação ingênua)

#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;
}

 

Acho que você gosta

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/112981622
Recomendado
Clasificación