题解:P7576 「PMOI-3」期望乘积

题目传送门

题目大意

给定一个序列 \(a\),每次询问一段区间 \(l\)\(r\),可以进行 \(0\)\(t\) 次操作,每次选定一个区间将其所有数 \(+1\)。给出最终序列所有数乘积之和,对 \(10007\) 取模。

思路分析

可以先考虑暴力 \(O(nq)\) 如何做。假设我们现在已经知道操作序列 \(c\),即每个数加了多少次,那么可以求出总操作次数。即 \(\sum_{i=1}^{n-1} \max(0,c_{i+1}-c_i)\),这里详见 P1969 [NOIP 2013 提高组] 积木大赛

由此,可以设计出一个状态 \(dp_{i,j,k}\) 为前 \(i\) 个数,总操作次数为 \(j\)\(c_i\)\(k\)。转移是显然的:

\[dp_{i,j,k}=(a_i+k)\times(\sum_{l=0}^{k-1} dp_{i-1,j-k+l,l} + \sum_{l=k}^n dp_{i-1,j,l}) \]

初始值:\(dp_{0,0,0}=1\)

时间复杂度 \(O(nq \times (t+1)^2)\)

可以尝试初步优化,发现 \(k \le j\),则有用的信息总数为 \(\frac{(t+1) \times (t+2)}{2}\),可以估算成 \(t^2\)

接下来考虑如何优化掉 \(n\)。发现如果知道了 \(dp_{i-1}\) 的所有信息,那么 \(dp_i\) 是可以通过固定的几个 \(dp_{i-1}\) 值相加得到的。所以考虑矩阵乘法,答案即为 \(l\)\(r\) 的所有矩阵乘在一起,然后乘上初始矩阵,区间乘可以用线段树维护。为了方便维护,将 \(dp_{i,j,k}\) 映射到 \(dp_{i,j \times (t+1)+k}\)

显然可以预处理出来不同的 \(t\) 值所对应的矩阵,然后乘上 \(a_i+k\) 即可,加上建树的时间复杂度为 \(O(n \times t^6)\)

然而查询的时间复杂度是 \(q \log n \times t^6\),很明显会超时。但其实不需要线段树两个矩阵相乘,只需要一个初始行矩阵就可以,这样乘法的复杂度就降到了 \(t^4\)

所以总时间复杂度大概是 \(O(n \times t^6 + q \log n \times t^4)\),这个时间复杂度可以通过该题。

ACcode

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INT_MAX (int)(1e18)
#define mid (l+r>>1)

const int N=1e5+10;
const int mod=10007;

int n,q,k;
int a[N],dp[N][16];

int len[4]={0,2,5,9};

int Ju[3][10][10]=
{
	{
		{1,0,1},
		{0,1,0},
		{0,1,1}
	},
	{
		{1,0,1,0,0,1},
		{0,1,0,0,1,0},
		{0,1,1,0,0,1},
		{0,0,0,1,0,0},
		{0,0,0,1,1,0},
		{0,0,0,1,1,1}
	},
	{
		{1,0,1,0,0,1,0,0,0,1},
		{0,1,0,0,1,0,0,0,1,0},
		{0,1,1,0,0,1,0,0,0,1},
		{0,0,0,1,0,0,0,1,0,0},
		{0,0,0,1,1,0,0,0,1,0},
		{0,0,0,1,1,1,0,0,0,1},
		{0,0,0,0,0,0,1,0,0,0},
		{0,0,0,0,0,0,1,1,0,0},
		{0,0,0,0,0,0,1,1,1,0},
		{0,0,0,0,0,0,1,1,1,1}
	}
};

struct node{
	int ju[10][10];
	
	void New_Node(int val){
		int las=0,nxt=1,add=2;
		for(int j=0;j<=len[k];j++){
			for(int i=0;i<=len[k];i++){
				if(j==nxt) las=nxt,nxt+=add,add++;
				ju[i][j]=Ju[k-1][i][j]*(val+j-las);
			}
		}
	}
}tr[N<<2],chu,sum;

inline int read(){
	int t=0,f=1;
	register char c=getchar();
	while(c<'0'||c>'9') f=(c=='-')?(-1):(f),c=getchar();
	while(c>='0'&&c<='9') t=(t<<3)+(t<<1)+(c^48),c=getchar();
	return t*f;
}

//将三维 dp i,j,k 映射到 i,j*(t+1)+k 上 

/*
30pts
int solve1(int L,int R){
	for(int i=0;i<=3;i++)
		for(int j=0;j<=3;j++)
			dp[L-1][i*(k+1)+j]=0;
	dp[L-1][0]=1;
	for(int i=L;i<=R;i++)
		for(int j=0;j<=k;j++)
			for(int l=0;l<=j;l++){
				dp[i][j*(k+1)+l]=0;
				cout<<"hou:"<<j*(k+1)+l<<"\n";
				for(int ls=0;ls<=j;ls++)
					if(ls<l) dp[i][j*(k+1)+l]+=dp[i-1][(j-l+ls)*(k+1)+ls],cout<<(j-l+ls)*(k+1)+ls<<" ";
					else dp[i][j*(k+1)+l]+=dp[i-1][j*(k+1)+ls],cout<<j*(k+1)+ls<<" ";
				dp[i][j*(k+1)+l]=dp[i][j*(k+1)+l]%mod*(a[i]+l)%mod;
				cout<<"\n";
			}
	int res=0;
	for(int i=0;i<=k;i++)
		for(int j=0;j<=i;j++) res=(res+dp[R][i*(k+1)+j])%mod;
	return res;
}
*/

node operator *(const node &x,const node &y){
	node z;
	for(int i=0;i<=len[k];i++)
		for(int j=0;j<=len[k];j++){
			z.ju[i][j]=0;
			for(int l=0;l<=len[k];l++) z.ju[i][j]+=x.ju[i][l]*y.ju[l][j];
			z.ju[i][j]%=mod;
		}
	return z;
}

void pushup(int bian){
	tr[bian]=tr[bian<<1]*tr[bian<<1|1];
}

void build(int bian,int l,int r){
	if(l==r){tr[bian].New_Node(a[l]);return;}
	build(bian<<1,l,mid);
	build(bian<<1|1,mid+1,r);
	pushup(bian);
}

void query(int bian,int l,int r,int L,int R){
	if(L<=l&&R>=r){
		for(int j=0;j<=len[k];j++){
			sum.ju[0][j]=0;
			for(int l=0;l<=len[k];l++)
				sum.ju[0][j]+=chu.ju[0][l]*tr[bian].ju[l][j];
			sum.ju[0][j]%=mod;
		}
		for(int i=0;i<=len[k];i++) chu.ju[0][i]=sum.ju[0][i];
		return;
	}
	if(L<=mid) query(bian<<1,l,mid,L,R);
	if(R>mid) query(bian<<1|1,mid+1,r,L,R);
}

int solve(int L,int R){
	chu.ju[0][0]=1;
	for(int i=1;i<=len[k];i++) chu.ju[0][i]=0;
	query(1,1,n,L,R);
	int res=0;
	for(int i=0;i<=len[k];i++) res=res+chu.ju[0][i];
	return res%mod;
}

void debug(int bian){
	for(int i=0;i<=len[k];i++){
		for(int j=0;j<=len[k];j++)
			cout<<tr[bian].ju[i][j]<<" ";
		cout<<"\n";
	}
	cout<<"\n";
}

signed main(){
	n=read(),q=read(),k=read();
	for(int i=1;i<=n;i++) a[i]=read();
	build(1,1,n);
	for(int i=1;i<=q;i++){
		int l=read(),r=read();
		cout<<solve(l,r)<<"\n";
	} 
	return 0;
}


posted @ 2025-03-27 21:53  ask_silently  阅读(19)  评论(0)    收藏  举报