D.小さなsrfゲーム(逆思考+ゲーム+ dp単調キュー/ラインセグメントツリーの最適化)

https://blog.csdn.net/zstuyyyyccccbbbb/article/details/112912657(最初に同様の質問を添付してください


アイデア:サンプルを観察すると、srfとqtcに対する答えは負の符号を取ることです。したがって、srfが最初に移動したときに取得されたスコア(qtcスコアの最大値)を考慮してください。

なぜマイナス記号を取るのですか?例:

2 2

1 2

srfが最初に2を獲得したので、qtcを取得する必要はありません。したがって、最初の答えは2です

Qtcを最初に、質問は実際にはqtc-srfによって取得された最大スコアを最初に検討することを意味します。同様に、現時点では、qtcをsrfと見なし、2が最適です。スコアは2です。最後の質問では、どうしてもsrf-qtcのスコアを出力するので、負の数を取ります。

したがって、ここでは、最初にsrfの状況を簡単に検討します。

まず、srfがiの位置をとった後、qtcはi +1からi + mまでの数値を取ることができますが、スワイプしている場合は、その後のsrfの状態に影響します。

この時点まで、このトピックは私たちにインスピレーションを与えました。現在の状態が衝突である場合は、逆戻りします。そして、それはおそらくdpのような転送です。

ここでは、昨日のビーコンタワーの問題を見て、デザインを模倣することができます。後ろから前に、dp [i]はsrfが番号iを取ることを示します。このとき、[i〜n]はsrffirst-qtcスコアの最大値を取得します。

転送を検討してください:dp [i] = a [i] -max(dp [i + 1〜i + m]);

この転送には独自の方法があり、グループの友達の方程式のデザインが異なり、転送も異なります。その後、私は一晩中気を失い、朝に自分の考えに従ってこの問題を実行しました。わからない場合は、他のグループの友達のブログを参照してください。

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

この転送はこんな感じです。srfはiを取ります。つまり、対戦相手はAlpha Dogであるため、答えをできるだけ小さくするために取得できる最大値を見つけます。[i + 1〜i + m]では、犬が先発者であり、以前に更新されたsrfの状態である最大状態を取り、最大の状態を選択してスコアを小さくします。(ゲーム)

最後に、最適な値を見つける必要があるdpがあります。私は単調なキューにあまり詳しくないので、ラインセグメントツリーに行きました。(単調キューの最適化は、上記のクラスターを参照できます)

(メモは素朴な方程式です)

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

 

おすすめ

転載: blog.csdn.net/zstuyyyyccccbbbb/article/details/112981622