题解:P13272 [NOI2025] 序列变换
简要题意: 定义一次操作:令 \(a_{i+1},a_i\) 同时减去 \(\min(a_i,a_{i+1})\)。可进行任意次操作。记 \(F(a)=\displaystyle\sum_{a_i=0}b_i,G(a)=\displaystyle\prod_{a_i=0}c_i\),对于操作可以得到的所有 \(a\),求 \(\max F(a)\) 和 \(\displaystyle\sum G(a)\)。
解法:
注意到这个操作会导致相邻两个数中较小的变成 \(0\),若两数中有 \(0\) 存在,则操作是无意义的。因此操作本质上可以刻画为:
0→...→0→x←0←...←0 左边 \((i,i+1)\),右边 \((i-1,i)\),最终收到中间某个位置,我们用 \((l,r,p)\) 表示一个从 \(l,r\) 两端收到中间 \(p\) 的操作。我们令两端收过来的数为 \(x,y\),则可以得到这样的关系:
-
\(x+y>a_p\) 显然 \(a_p\) 并不能作为中心点,不成立。
-
\(x+y=a_p\) 此时两端收完之后会恰好将 \(a_p\) 变成 \(0\),于是形成一个 \([l,r]\) 的连续 \(0\) 段。
-
\(x+y<a_p\) 此时两端收完会在中间留下非零的数,形成 \(0\) 段 \([l,p)\) 和 \((p,r]\)。
\(\max F(a)\)
操作都是一个区间,因此可以设计一个 \(\mathrm{dp}\),定义 \(f_i\) 表示考虑前 \(i\) 个数,能得到的 \(\max F(a)\)。
可以不选 \(i\),因此恒有 \(f_i\leftarrow f_{i-1}\)。
然后考虑一个操作 \((j,i,p)\) 的贡献,此时有 \(f_i\leftarrow f_{j-1}+w(j,i,p)\)。其中 \(w(j,i,p)\) 表示这个操作对和的贡献,显然有 \(w(l,r,p)=\displaystyle\sum_{i=l}^{p-1}b_i+\displaystyle\sum_{i=p+1}^{r}b_i+[x+y=a_p]\times b_p\)
可以通过一个预处理求出 \(x,y\),\(\mathrm{dp}\) 部分此时做到 \(O(n^3)\)。
\(\displaystyle\sum G(a)\)
显然此时可以直接仿照 \(\max F(a)\) 的计数方式,用 \(g_i\) 表示前 \(i\) 个数的 \(\sum G(a)\),则有转移 \(g_i\leftarrow g_{i-1}\) 和 \(g_i\leftarrow g_{j-1}\times \prod(j,i,p)\)。较难处理的点就是要对本质不同的 \(a\) 进行这个计数,在最大值求的时候没有这个限制,但是此处要求和,所以要防止记重,考虑什么时候会算重。如果 \(x+y=a_p\),即整个 \([l,r]\) 都被覆盖,那么 \(p\) 取到任何位置对应的序列都是相同的,所以此时只应计算一次。考虑 \([1,1,1,1]\) 的情况,此时选择 \([1,2],[3,4]\) 消除的序列和选择 \([1,4]\) 消除的序列是本质相同的,其漏洞在 \(\mathrm{dp}\) 中体现为将两边已经全部消成 \(0\) 的序列拼接起来,因此,我们可以钦定两边不能都被消成 \(0\),即不能出现操作完之后都是 \(0\) 的情况,这样就保证了被划分的区间数量最大化,也就完成了去重。
优化
前面的做法可以做到 \(O(n^3)\),考虑优化。我们可以维护一个 \(lp_i,rp_i\) 表示每个点可以向左向右拓展到的最远点,那么可以被两边走到的转移点就是 \(p\in [\max(j,lp_i-1),\min(i,rp_j+1)]\),于是我们只需要分析 \(x+y\) 和 \(a_p\) 的关系。
考虑向左走的过程和向右走的过程中每个数对 \(x+y-a_p\) 的贡献,不难发现就是 ...→+→-→+→-→+←-←+←-←+←... 的正负,即和为 \(x+y-a_p=\displaystyle\sum_{i\in[l,r]}(-1)^{i-p}a_i\),于是所有奇偶性相同的 \(p\) 位置的 \(x+y-a_p\) 都是相同的!因此直接对奇偶分类处理即可,具体的,对于每个区间维护奇偶的 \(\max \set{-b_i},\sum c_i^{-1}\) 即可。时间复杂度 \(O(n^2)\)。
\(O(n^3)\):
cin >> n;
for (int i=1;i<=n;i++) cin >> a[i];
for (int i=1;i<=n;i++)
{
cin >> b[i];
Sumb[i]=Sumb[i-1]+b[i];
}
prod[0]=inv[0]=1;
for (int i=1;i<=n;i++)
{
cin >> c[i];
prod[i]=(ll)prod[i-1]*c[i]%mod;
inv[i]=qmi(prod[i],mod-2);
}
for (int i=1;i<=n;i++)
{
fill(val[i]+1,val[i]+n+1,-INF); val[i][i]=a[i];
lp[i]=rp[i]=i;
for (int j=i+1;a[j]>val[i][j-1] && j<=n;j++)
{
val[i][j]=a[j]-val[i][j-1];
rp[i]=j;
}
for (int j=i-1;a[j]>val[i][j+1] && j>=1;j--)
{
val[i][j]=a[j]-val[i][j+1];
lp[i]=j;
}
}
g[0]=1;
for (int i=1;i<=n;i++)
{
f[i]=f[i-1]; g[i]=g[i-1];
bool cov=false;
for (int j=1;j<i;j++)
{
for (int p=max(j,lp[i]-1);p<=min(i,rp[j]+1);p++)
{
int x=p!=j ? val[j][p-1] : 0;
int y=p!=i ? val[i][p+1] : 0;
if (x+y>a[p]) continue;
ll v=sumb(j,p-1)+sumb(p+1,i)+(x+y==a[p] ? b[p] : 0);
Max(f[i],f[j-1]+v);
if (x+y==a[p])
{
if (!cov) adm(g[i],(ll)g[j-1]*prd(j,i)%mod);
cov=true;
}
else
{
ll coef=(ll)prd(j,p-1)*prd(p+1,i)%mod;
adm(g[i],(ll)g[j-1]*coef%mod);
}
}
}
}
cout << f[n] << " " << g[n] << "\n";
\(O(n^2)\) 正解:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
inline int Mod(int x) { return x<0 ? x+mod : (x>=mod ? x-mod : x); }
inline void adm(int &x,int y) { x=Mod(x+y); }
inline int qmi(ll a,int b)
{
ll res=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) res=res*a%mod;
return res;
}
template<class T>void Max(T &x,T y) { if (y>x) x=y; }
const int N=5010,INF=1e9+10;
int n;
int a[N],b[N],c[N];
ll preb[N];
int prod[N],inv[N],ic[N];
int prd(int l,int r) { return l>r ? 1 : (ll)prod[r]*inv[l-1]%mod; }
int val[N][N],lp[N],rp[N];
ll vs[N];
int mx[2][N][N],iv[2][N][N];
ll f[N];
int g[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int id,T;
cin >> id >> T;
while (T--)
{
cin >> n;
for (int i=1;i<=n;i++) cin >> a[i];
for (int i=1;i<=n;i++)
{
cin >> b[i];
preb[i]=preb[i-1]+b[i];
}
prod[0]=inv[0]=1;
for (int i=1;i<=n;i++)
{
cin >> c[i];
prod[i]=(ll)prod[i-1]*c[i]%mod;
ic[i]=qmi(c[i],mod-2);
inv[i]=(ll)inv[i-1]*ic[i]%mod;
}
for (int i=1;i<=n;i++)
{
fill(val[i]+1,val[i]+n+1,-INF); val[i][i]=a[i];
lp[i]=rp[i]=i;
for (int j=i+1;a[j]>val[i][j-1] && j<=n;j++)
{
val[i][j]=a[j]-val[i][j-1];
rp[i]=j;
}
for (int j=i-1;a[j]>val[i][j+1] && j>=1;j--)
{
val[i][j]=a[j]-val[i][j+1];
lp[i]=j;
}
}
for (int l=1;l<=n;l++)
{
fill(mx[0][l],mx[0][l]+n+1,-INF);
fill(mx[1][l],mx[1][l]+n+1,-INF);
fill(iv[0][l],iv[0][l]+n+1,0);
fill(iv[1][l],iv[1][l]+n+1,0);
for (int r=l;r<=n;r++)
{
mx[0][l][r]=mx[0][l][r-1],mx[1][l][r]=mx[1][l][r-1];
iv[0][l][r]=iv[0][l][r-1],iv[1][l][r]=iv[1][l][r-1];
Max(mx[r&1][l][r],-b[r]);
adm(iv[r&1][l][r],ic[r]);
}
int coef=(l&1) ? -1 : 1;
vs[l]=vs[l-1]+coef*a[l];
}
g[0]=1;
for (int i=1;i<=n;i++)
{
f[i]=f[i-1]; g[i]=g[i-1];
bool cov=false;
for (int j=1;j<i;j++)
{
int l=max(j,lp[i]-1),r=min(i,rp[j]+1);
if (l>r) continue;
bool flg=false;
ll sb=preb[i]-preb[j-1];
int cof=(ll)prod[i]*inv[j-1]%mod;
auto work = [&](int op)
{
ll s=(vs[i]-vs[j-1])*(!op ? 1 : -1);
if (s>0)
{
adm(g[i],(ll)g[j-1]*cof%mod*iv[op][l][r]%mod);
Max(f[i],f[j-1]+sb+mx[op][l][r]);
}
else if (s==0)
{
if (!flg)
{
adm(g[i],(ll)g[j-1]*cof%mod);
flg=true;
}
Max(f[i],f[j-1]+sb);
}
};
if (l==r) work(l&1);
else { work(0),work(1); }
}
}
cout << f[n] << " " << g[n] << "\n";
}
return 0;
}

浙公网安备 33010602011771号