【ROIR2020Day2】海报
【ROIR2020Day2】海报
by AmanoKumiko
Description
你的朋友们为了会见 IOI 回来的国家队选手准备了很多漂亮的海报,现在就还差要考虑些细节了。
为了欢迎这些选手,你的 个朋友会拿着海报站成一个圈。为了方便描述,我们把他们编号为朋友 1...n,其中对于 \(i∈[1,n-1]\),朋友 i和朋友 i+1站在一起,且朋友 n和朋友 1站在一起。
每张海报都有一个美观度,其中朋友 i拿着的海报的美观度为 ai。当开始庆祝时,一些朋友会举起他们的海报。为了美观,不能有 4个或以上排在一起的朋友同时举起他们的海报。
为了能够丰富节目效果,你的朋友们还打算在庆祝过程中更换 q次海报。每次更换后,海报 pi的美观度将变为 qi。你的朋友想知道每次更换后在符合上述条件下的最大美观度之和。
你的任务是给出初始的美观度,求出初始以及各次更换后的最大美观度之和。
Input
第一行一个整数n ,朋友总数。
接下来一行n 个整数 ai,表示初始美观度。
第三行 q个整数表示海报更换次数。
接下来 q行每行两个整数pi,vi ,描述一次更换。
Output
输出 q+1行,表示初始时及各次更换后最大的美观度之和。
Sample Input
6
1 2 3 4 5 6
2
6 0
2 5
Sample Output
17
13
15
Data Constraint
\(n<=4\times10^4,0<=q<=4\times10^4,0<=ai,vi<=10^9,1<=pi<=n\)
Solution
纪念第一次在考场打动态DP
暴力显然DP
设\(f[i][j]\)表示前\(i\)个位置,后\(j\)个分为一段的最大值
那么
但是这样难以考虑环的情况
可以暴力一点,再开一维k,表示下标从1开始的那一段选了k个
在第n个位置判一下\(j+k<=3\)即可
我比较懒所以前3个位置写了暴力QvQ
研究一下f的转移,可以发现是动态DP的类型
那么设
那么\(C[i]=max_{j=0}^{3}A[j]+B[j][i]\)
这个加起来再求max的操作可以看成广义的矩阵乘法,它满足结合律(见NOIP2018保卫王国)
那么线段树上的每个点维护当前区间转移矩阵的乘积,每次单点修改矩阵
时间复杂度\(O(4^3Qlog_2N)\)
Code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(register int i=a;i<=b;i++)
#define fd(i,a,b) for(register int i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a));
#define LL long long
#define inf 400000000000000
#define N 40010
#define ls x<<1
#define rs (x<<1)|1
int n,q,p;
LL fs[4][4],ft[4][4],ans,a[N],v;
struct matrix{LL v[4][4];}res;
matrix operator+(const matrix&le,const matrix &ri){
memset(res.v,0,sizeof(res.v));
fo(i,0,3) fo(j,0,3) fo(k,0,3)res.v[i][j]=max(res.v[i][j],le.v[i][k]+ri.v[k][j]);
return res;
}
struct tree{
matrix s[N*4];
void change(int x,int l,int r,int pos){
if(l==r){
s[x].v[0][1]=s[x].v[1][2]=s[x].v[2][3]=a[l];
return;
}
int mid=l+r>>1;
if(pos<=mid)change(ls,l,mid,pos);
else change(rs,mid+1,r,pos);
s[x]=s[ls]+s[rs];
}
void build(int x,int l,int r){
if(l==r){
fo(i,0,3) fo(j,0,3)s[x].v[i][j]=-inf;
s[x].v[0][1]=s[x].v[1][2]=s[x].v[2][3]=a[l];
s[x].v[0][0]=s[x].v[1][0]=s[x].v[2][0]=s[x].v[3][0]=0;
return;
}
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
s[x]=s[ls]+s[rs];
}
}t;
void dfs(int x,int y,LL z,int w,bool flag){
if(x>3){fs[y][w]=max(fs[y][w],z);return;}
dfs(x+1,y+1,z+a[x],flag?w+1:w,flag);dfs(x+1,0,z,w,0);
}
namespace IO{
const int sz=1<<22;
char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
inline char gc(){return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;}
template<class T>void read(T& x){
x=0;char c=gc();
for(;c<'0'||c>'9';c=gc());
for(;c>='0'&&c<='9';c=gc())x=x*10+(c-'0');
}
inline void flush(){fwrite(b,1,t-b,stdout),t=b;}
inline void pc(char x){*t++=x;if(t-b==sz)flush();}
template<class T> void write(T x,char c='\n'){
if(x==0)pc('0');int t=0;
for(;x;x/=10)p[++t]=x%10+'0';
for(;t;--t)pc(p[t]);pc(c);
}
struct F{~F(){flush();}}f;
}
using IO::read;
using IO::write;
int main(){
read(n);
fo(i,1,n)read(a[i]);
if(n>=5)t.build(1,4,n-1);
read(q);
fo(i,0,q){
if(i){
read(p);read(v);a[p]=v;
if(p>3&&p<n)t.change(1,4,n-1,p);
}
ans=0;
mem(fs,0);mem(ft,0);
dfs(1,0,0,0,1);
if(n>=5){
matrix q=t.s[1];
fo(j,0,3) fo(k,0,3) fo(l,0,3)ft[j][k]=max(ft[j][k],fs[l][k]+q.v[l][j]);
fo(j,1,3) fo(k,0,3-j)ans=max(ans,ft[j-1][k]+a[n]);
fo(j,0,3) fo(k,0,3)ans=max(ans,ft[j][k]);
}else{
fo(j,1,3) fo(k,0,3-j)ans=max(ans,fs[j-1][k]+a[n]);
fo(j,0,3) fo(k,0,3)ans=max(ans,fs[j][k]);
}
write(ans);
}
return 0;
}