被 greedy 整破防了。

这是转换后的题面。
考虑使用调整法构造,记 2 个序列分别为 f,g,那么一种调整法是,f 加了没事就加了不管,否则我们再考虑往当前已经构造的序列的最大值的后方加一段正贡献的 g。
显然这个很对了,但有点假(
我们考虑前缀和,那么前面的要尽可能大,一个方向的一味扩展有时候可能当前没事但会导致后面出事。
那么,我们就要当前能加多大就多大,这个加是按当前 f 的正负分类的。若 f 为正,显然直接加,然后再看看 g 那边能否有正贡献。因为初始越大,所能在 g 得到的贡献期望越大。若 f 为负,我们可以看看拿当前的往 g 扩展正贡献,然后再看看能不能不出事。
然后 O(n2) 到 O(nlogn) trick 一下二分 + ST 表就好了。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(2e5+5);
int a[N],n,p,f[N],g[N],tot1,tot2,st1[23][N],st2[23][N],stp[23][N],sum[N];
int qrymi(int l,int r) {
int qwq=log2(r-l+1);
return min(st1[qwq][l],st1[qwq][r-(1<<qwq)+1]);
}
int qrymx(int l,int r) {
int qwq=log2(r-l+1);
return max(st2[qwq][l],st2[qwq][r-(1<<qwq)+1]);
}
int qrymxp(int l,int r) {
int qwq=log2(r-l+1);
if(st2[qwq][l]>=st2[qwq][r-(1<<qwq)+1]) return stp[qwq][l];
return stp[qwq][r-(1<<qwq)+1];
}
void sol() {
cin>>n>>p;
for(int i=1;i<=n;i++) cin>>a[i];
tot1=tot2=0;
for(int i=p+1;i<=n;i++) f[++tot1]=a[i];
for(int i=p-1;i>=1;i--) g[++tot2]=a[i];
for(int i=1;i<=tot2;i++) sum[i]=sum[i-1]+g[i];
for(int i=1;i<=tot2;i++) {
st1[0][i]=sum[i]; st2[0][i]=sum[i]; stp[0][i]=i;
}
for(int i=1;(1<<i)<=tot2;i++) {
for(int j=1;j+(1<<i)-1<=tot2;j++) {
st1[i][j]=min(st1[i-1][j],st1[i-1][j+(1<<(i-1))]);
st2[i][j]=max(st2[i-1][j],st2[i-1][j+(1<<(i-1))]);
if(st2[i][j]==st2[i-1][j]) stp[i][j]=stp[i-1][j];
else stp[i][j]=stp[i-1][j+(1<<(i-1))];
}
}
int res=a[p],nw1=0,nw2=0;
bool ok=1;
while(nw1<tot1) {
if(f[nw1+1]>=0) {
res+=f[nw1+1]; ++nw1;
int x=res,mx=0,pos=0;
int l=nw2+1,r=tot2;
while(l<=r) {
int mid=(l+r)>>1;
if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
else r=mid-1;
}
if(!pos) {
continue ;
}
mx=qrymx(nw2+1,pos)-sum[nw2]+res;
pos=qrymxp(nw2+1,pos);
if(mx>res) {
res=mx; nw2=pos;
}
} else {
int x=res,mx=0,pos=0;
int l=nw2+1,r=tot2;
while(l<=r) {
int mid=(l+r)>>1;
if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
else r=mid-1;
}
if(!pos) {
if(res+f[nw1+1]<0) {
ok=0; break ;
}
res+=f[nw1+1]; ++nw1;
continue ;
}
mx=qrymx(nw2+1,pos)-sum[nw2]+res;
pos=qrymxp(nw2+1,pos);
if(mx>res) {
res=mx; nw2=pos;
}
if(res+f[nw1+1]<0) {
ok=0; break ;
}
res+=f[nw1+1]; ++nw1;
}
}
if(nw1!=tot1) ok=0;
if(ok) {
cout<<"YES\n"; return ;
}
tot1=tot2=0;
for(int i=p-1;i>=1;i--) f[++tot1]=a[i];
for(int i=p+1;i<=n;i++) g[++tot2]=a[i];
for(int i=1;i<=tot2;i++) sum[i]=sum[i-1]+g[i];
for(int i=1;i<=tot2;i++) {
st1[0][i]=sum[i]; st2[0][i]=sum[i]; stp[0][i]=i;
}
for(int i=1;(1<<i)<=tot2;i++) {
for(int j=1;j+(1<<i)-1<=tot2;j++) {
st1[i][j]=min(st1[i-1][j],st1[i-1][j+(1<<(i-1))]);
st2[i][j]=max(st2[i-1][j],st2[i-1][j+(1<<(i-1))]);
if(st2[i][j]==st2[i-1][j]) stp[i][j]=stp[i-1][j];
else stp[i][j]=stp[i-1][j+(1<<(i-1))];
}
}
res=a[p],nw1=0,nw2=0;
ok=1;
while(nw1<tot1) {
if(f[nw1+1]>=0) {
res+=f[nw1+1]; ++nw1;
int x=res,mx=0,pos=0;
int l=nw2+1,r=tot2;
while(l<=r) {
int mid=(l+r)>>1;
if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
else r=mid-1;
}
if(!pos) {
continue ;
}
mx=qrymx(nw2+1,pos)-sum[nw2]+res;
pos=qrymxp(nw2+1,pos);
if(mx>res) {
res=mx; nw2=pos;
}
} else {
int x=res,mx=0,pos=0;
int l=nw2+1,r=tot2;
while(l<=r) {
int mid=(l+r)>>1;
if(qrymi(nw2+1,mid)-sum[nw2]+res>=0) l=mid+1,pos=mid;
else r=mid-1;
}
if(!pos) {
if(res+f[nw1+1]<0) {
ok=0; break ;
}
res+=f[nw1+1]; ++nw1;
continue ;
}
mx=qrymx(nw2+1,pos)-sum[nw2]+res;
pos=qrymxp(nw2+1,pos);
if(mx>res) {
res=mx; nw2=pos;
}
if(res+f[nw1+1]<0) {
ok=0; break ;
}
res+=f[nw1+1]; ++nw1;
}
}
if(nw1!=tot1) ok=0;
if(ok) {
cout<<"YES\n"; return ;
}
cout<<"NO\n";
}
signed main() {
cin.tie(0); ios::sync_with_stdio(false);
int T; cin>>T; while(T--) sol();
return 0;
}
不妨类增量构造的方式思考一下其生成方式。
若第 k 轮,那么显然当前有 2k 个,要生成到下一部分,即 ∀i∈[0,2k),si+2k=¬si,不妨考虑从二进制下看,显然二者只有 k 这一位不同,也就是说其 1 的个数的奇偶性是不同的。
那么根据第 0 位为 0,以及如此增量构造归纳一下,不难得出,si=popcount(i)&1。
但是这让我们来找不同还是很困难!
考虑找不同是 i,i+n 的 1 的奇偶性,解决这么大规模的问题要么通项要么数位 dp。显然我们先尝试后者。
发现就是一个带进位的,类 https://www.cnblogs.com/xugangfan/p/16442268.html 做就好了。
当然,如果你能发现这个条件等价于 i,i+n 不同的位个数为奇数,那么可以省掉一维。
证明,考虑记不同的在 i 下是 a 个 1,以及 b 个 0,二者相同的有 c 个 1,那么第一个条件即为 c+a≢c+b(mod2),即 a≢b(mod2),即 a≡−b+1(mod2),然后移过去就好了。
为什么有傻逼思考的时候忘了 GDOI 2021 PJ 的教训。
显然为了同一,移过去,发现是不同行,任意 2 列的差值不同,又根据 n 是奇数,构造公差各不相同的等差数列即可。
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】