【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\)个分为一段的最大值

那么

\[f[i][j]=\begin{cases} f[i-1][j-1]+a[i],j∈[1,3]\\ max_{k=0}^{k=3}\ \ f[i-1][k],j=0\\ \end{cases} \]

但是这样难以考虑环的情况

可以暴力一点,再开一维k,表示下标从1开始的那一段选了k个

在第n个位置判一下\(j+k<=3\)即可

我比较懒所以前3个位置写了暴力QvQ

研究一下f的转移,可以发现是动态DP的类型

那么设

\[A= \left\{ \begin{matrix} f[i][0]&f[i][1]&f[i][2]&f[i][3] \end{matrix} \right\} \]

\[B= \left\{ \begin{matrix} 0&a[i+1]&-inf&-inf\\ 0&-inf&a[i+1]&-inf\\ 0&-inf&-inf&a[i+1]\\ 0&-inf&-inf&-inf \end{matrix} \right\} \]

\[C= \left\{ \begin{matrix} f[i+1][0]&f[i+1][1]&f[i+1][2]&f[i+1][3] \end{matrix} \right\} \]

那么\(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;
}
posted @ 2021-07-19 20:15  冰雾  阅读(111)  评论(0编辑  收藏  举报