Solution P7482 | Best Wishes
一个好写
考虑对于每个右端点计算答案。
众所周知,最大独立集问题是可以 DP 的。具体地,维护两个 DP 值
若在末尾加入一个值为
这类问题有一个经典转化(类似 PKUSC2024 D1T3)。把转移式子写成以下形式:
发现每次新加入一个数,
也就是说,我们将答案进行拆贡献,每加入一个数,答案就增加
我们从左往右扫,假设扫到
记录
实时维护
如果不考虑要与
发现会有一些
手动改成
于是我们可以在
具体实现的时候发现
ll n,a[100005],tx=1,ty=0,sum=0,ans=0,Ans=0;
deque<P>S;
// tx, ty 是全局 tag,S 中的一个数 x 其实已经变成了 tx * x + ty
// tx 为 1 或 -1,所以序列有时候升序有时候降序,但时刻保持有序
ll decode(ll x){ return tx * x + ty; } // 还原真正的 x
ll encode(ll x){ return (x - ty) / tx; } // 加入的时候需要进行逆操作
void solve(){
n=read();
for(ll i=1;i<=n;i++) a[i]=read();
for(ll i=1;i<=n;i++){
if(S.empty() || encode(0) <= S.front().fi) S.push_front(mkp(encode(0), 1));
else S.push_back(mkp(encode(0), 1));
tx=-tx; sum=mod-sum;
ty=-ty+a[i]; sum=(sum+a[i]*i)%mod; // 全局修改
ll cnt = 0;
while(!S.empty() && decode(S.front().fi) < 0){
sum=(sum+(-decode(S.front().fi))*(S.front().se))%mod;
cnt+=S.front().se; S.pop_front();
}
while(S.size() && decode(S.back().fi) < 0){
sum=(sum+(-decode(S.back().fi))*(S.back().se))%mod;
cnt+=S.back().se; S.pop_back();
} // 对首尾的特殊修改
// sum 是 r[x] 的变化量
if(S.empty() || encode(0) <= S.front().fi) S.push_front(mkp(encode(0), cnt));
else S.push_back(mkp(encode(0), cnt));
_Add(ans, sum); // ans 是 r[x]
_Add(Ans, ans); // Ans 是总的答案
}
printf("%lld\n", Ans);
}