题目
题目链接:https://loj.ac/p/3264
(n,qleq 40000)。
思路
最多能连续选 (3) 个人以及单点修改就已经把动态 dp 提示的非常明显了。
我们可以通过枚举前 (3) 个人选或不选来把环上的问题转化为序列上的问题。等价于选出若干个人价值最小且相邻 (4) 个人中至少需要选择一个。那么直接维护一个 (4 imes 4) 的矩阵 ddp 随便搞搞就好了。
时间复杂度 (O(Qk^3log n))。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=40010,M=4;
const ll Inf=1e18;
int n,Lim,Q,a[N];
ll sum;
int read()
{
int d=0; char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
struct Matrix
{
ll a[M+1][M+1];
Matrix() { memset(a,0x3f3f3f3f,sizeof(a)); }
friend Matrix operator *(Matrix a,Matrix b)
{
Matrix c;
for (int i=1;i<=Lim;i++)
for (int j=1;j<=M;j++)
for (int k=1;k<=M;k++)
c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
}res;
struct SegTree
{
Matrix f[N*4];
void update(int x,int l,int r,int k)
{
if (l==r)
{
f[x].a[1][1]=a[l]; f[x].a[1][2]=0; f[x].a[1][3]=Inf; f[x].a[1][4]=Inf;
f[x].a[2][1]=a[l]; f[x].a[2][2]=Inf; f[x].a[2][3]=0; f[x].a[2][4]=Inf;
f[x].a[3][1]=a[l]; f[x].a[3][2]=Inf; f[x].a[3][3]=Inf; f[x].a[3][4]=0;
f[x].a[4][1]=a[l]; f[x].a[4][2]=Inf; f[x].a[4][3]=Inf; f[x].a[4][4]=Inf;
return;
}
int mid=(l+r)>>1;
if (k<=mid) update(x*2,l,mid,k);
else update(x*2+1,mid+1,r,k);
f[x]=f[x*2]*f[x*2+1];
}
}seg;
void solve()
{
ll ans=Inf;
for (int s=0;s<8;s++)
{
ll ans1=0; int l=4,r=0;
for (int i=1;i<=3;i++)
if (s&(1<<i-1))
{
ans1+=a[i]; r=i;
if (l==4) l=i;
}
res.a[1][1]=res.a[1][2]=res.a[1][3]=res.a[1][4]=Inf;
res.a[1][4-r]=ans1;
Lim=1; res=res*seg.f[1]; Lim=M;
for (int i=1;l+i<=5;i++)
ans=min(ans,res.a[1][i]);
}
cout<<sum-ans<<"
";
}
int main()
{
Lim=M;
n=read();
for (int i=1;i<=n;i++)
{
a[i]=read(); sum+=a[i];
if (i>=4) seg.update(1,4,n,i);
}
solve();
Q=read();
while (Q--)
{
int x;
x=read(); sum-=a[x];
a[x]=read(); sum+=a[x];
if (x>=4) seg.update(1,4,n,x);
solve();
}
return 0;
}