CF1540E - Tasty Dishes

CF1540E - Tasty Dishes

题目大意

给定序列\(a_i\),保证\(|a_i|\leq i\)

以及一个变换:

\(\displaystyle a_i\leftarrow \sum_{j\in S_i} max\{a_j,0\}\cdot j+\left\{\begin{aligned} a_i && a_i\leq 0 \\ i\cdot a_i && a_i>0\end{aligned}\right.\),并且保证\(\forall j\in S_i,j>i\)

要求维护\(q\)个操作:

1.查询在初始值上进行\(k\)轮变换后,\(\sum_{i=l}^r a_i\)的值

2.修改初始值,令\(a_i\leftarrow a_i+x\),保证\(x\ge 0\)


分析

操作分析

首先观察变换的过程和修改操作,容易发现:

1.每个数\(a_i\)在第一个\(>0\)的时刻开始贡献转移,设这个时间为\(d_i\)

2.当一个数\(a_i\leftarrow a_i+a_j\cdot j (a_j>0)\),由于\(a_i\ge -i\),新的\(a_i\)一定\(>0\)

3.只有\(a_i\leq 0,a_i+x>0\)的情况,修改操作会对\(d_i\)产生影响

那么实际上我们可以在每个\(a_i\leq 0,a_i+x>0\)的修改时重构,由于只有\(n\)次重构,这一部分复杂度为\(O(n^3)\)

设转移矩阵\(A_{i,j}=[j\in S_i\ or\ j=i] \cdot j\)

\(e_i\)为一个只有第\(i\)项为\(1\)的列向量

\(k\ge d_i\),则我们要求\(\sum A^{k-d_i} e_i a_i\)

固然不能每次都求矩阵幂,即便是预处理之后用\(O(n^2\log k)\)的复杂度依然不可取

加速矩阵幂

考虑到给定矩阵的特殊性,考虑用 矩阵特征值 来优化

由于\(A\)是一个上三角矩阵,那么一定满足\(A_{i,i}\)都是其特征值,而这题限定了\(A_{i,i}=i\)

\(A\)\(n\)个特征值,并且由于\(A\)是上三角矩阵,可以在\(O(n^3)\)时间消元得到每个\(i\)对应的特征向量\(v_i\)

模拟这个过程也容易发现,\(v_i\)构成的矩阵\(\begin{bmatrix} \array{v_1 & v_2 &\cdots &v_n}\end{bmatrix}\)是一个上三角矩阵

在所求的式子中并不存在有关\(v_i\)的表达式,但是有列向量\(e_i\),并且\(v_i\)线性无关

因此我们以\(n\)\(v_i\)作为基底替换\(c\),构造矩阵\(c\),满足\(e_i=\sum c_{i,j} v_j\)

形式化的,就是

\(c \cdot \begin{bmatrix} \array{&&v_1^T &&\\ && v_2^T &&\\ &&\cdots&& \\ &&v_n^T&&}\end{bmatrix}=\begin{bmatrix} \array{&&e_1^T &&\\ && e_2^T &&\\ &&\cdots&& \\ &&e_n^T&&}\end{bmatrix}\)

而右边是一个单位矩阵,故实际上这个操作就是求矩阵逆,而这个矩阵是满秩的


此时,答案式子替换为\(\displaystyle \sum A^{k-d_i}\sum c_{i,j}v_ja_i\),再带入特征值的定义\(Av_i=iv_i\)

转化为\(\displaystyle \sum a_i \sum j^{k-d_i}c_{i,j}v_j\)

我们可以预处理\(v_{j,k}\)的前缀和,容易求得\(v_{j,[l,r]}\)

再将\(k-d_i\)参数分离,只需要维护\(s_j=\sum_i a_i c_{i,j} j^{-d_i}\),所有的幂次均可以预处理得到

由于不一定满足\(k\ge d_i\),因此需要用数据结构维护前缀和,复杂度为\(O(qn\log n)\)

如果线性预处理树状数组,则重构总复杂度为\(O(n^3)\)

Codeforces Submission

const int N=310,INF=1e9+10,P=1e9+7;

int n,m,q;
int a[N],A[N][N],V[N][N],SV[N][N],C[N][N];
int F[N];
ll qpow(ll x,ll k=P-2){
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
int D[N];
bitset <N> B[N],All;
struct Tree{
	int s[N],t[N];
	void clr(){ memset(t,0,(m+1)<<2); }
	void Build(){ rep(i,1,m) t[i]+=t[i-1],Mod1(t[i]),s[i]=t[i]-t[i&(i-1)],Mod2(s[i]); }
	void Add(int p,int x) {
		t[m]+=x,Mod1(t[m]);
		p++;
		while(p<=m) s[p]+=x,Mod1(s[p]),p+=p&-p;
	}
	int Que(int p) {
		int r=0;
		cmin(++p,m);
		if(p==m) return t[p];
		while(p) r+=s[p],Mod1(r),p-=p&-p;
		return r;
	}
} T[N];
int W[N][N],Inv[N][N],Pow1[N][1010],Pow2[N][1<<10];

void Make(){
	All.reset();
	rep(i,1,n) if(a[i]>0) D[i]=0,All[i]=1,All|=B[i];
	else D[i]=INF;
	m=0;
	rep(i,1,n) rep(j,1,n) if(D[j]==INF && All[j]) D[j]=i,All|=B[j];
	rep(i,1,n) if(D[i]<INF) cmax(m,D[i]);
	m++;
	rep(i,1,n) T[i].clr();
	rep(i,1,n) if(D[i]<INF) rep(j,1,n) W[i][j]=1ll*C[i][j]*Inv[j][D[i]]%P,T[j].t[D[i]+1]=(T[j].t[D[i]+1]+1ll*W[i][j]*(P+a[i]))%P;
	rep(i,1,n) T[i].Build();
}

int main() {
	n=rd();
	rep(i,1,n) {
		Inv[i][0]=1,Inv[i][1]=qpow(i);
		rep(j,2,n) Inv[i][j]=1ll*Inv[i][j-1]*Inv[i][1]%P;
	}
	rep(i,1,n) 	rep(j,*Pow1[i]=1,1000) Pow1[i][j]=1ll*Pow1[i][j-1]*i%P;
	rep(i,1,n) a[i]=rd();
	rep(i,1,n) rep(j,A[i][i]=1,rd()) A[i][rd()]=1;
	rep(i,1,n) rep(j,i+1,n) if(A[i][j]) B[j][i]=1;
	rep(i,1,n) rep(j,1,n) A[i][j]*=j;
	rep(i,1,n) drep(j,i-1,V[i][i]=1) {
		rep(k,j+1,i) V[i][j]=(V[i][j]+1ll*A[j][k]*V[i][k])%P;
		V[i][j]=V[i][j]*qpow(i-j)%P;
	}
	rep(i,1,n) rep(j,1,n) SV[i][j]=SV[i][j-1]+V[i][j],Mod1(SV[i][j]);
	rep(i,1,n) C[i][i]=1;
	rep(i,1,n) rep(j,1,i-1) rep(k,1,n) C[i][k]=(C[i][k]+1ll*(P-V[i][j])*C[j][k])%P;
	Make();
	rep(_,1,rd()) {
		int opt=rd();
		if(opt==2){
			int i=rd(),x=rd(); a[i]+=x;
			if(a[i]-x<=0 && a[i]>0) Make();
			else if(D[i]<INF && x) rep(j,1,n) T[j].Add(D[i],1ll*W[i][j]*x%P);
		} else {
			int k=rd(),l=rd(),r=rd();
			int ans=0;
			rep(j,1,n) ans=(ans+1ll*(SV[j][r]-SV[j][l-1]+P)*T[j].Que(k)%P*Pow1[j][k])%P;
			//rep(i,1,n) if(D[i]<=k) ans=(ans+1ll*w*C[i][j]%P*qpow(j,k-D[i])%P*(P+a[i]))%P;
			rep(i,l,r) if(D[i]>k) ans+=a[i],Mod2(ans);
			printf("%d\n",ans);
		}
	}
}
posted @ 2021-09-29 08:13  chasedeath  阅读(153)  评论(0编辑  收藏  举报