题解:CF1970E2 Trails (Medium)

前置知识

E1:dp。

E2:矩阵快速幂。

思路

暴力 dp

不难想到一个思路就是暴力 dp。

dpi,jdp_{i,j} 表示走了 ii 天,到达点 jj 的方案数,显然有方程:

dpi,j=k=1n(sumj×sumklj×lk)dpi1kdp_{i,j}=\sum_{k=1}^{n}(sum_j\times sum_k-l_j\times l_k)dp_{i-1}{k}

其中 sumj=lj+sjsum_j=l_j+s_j

原因很明显:如果没有限制,根据乘法原理,可以有 sumj×sumksum_j\times sum_k 种。但是有了限制,全选长的就不行,答案就得剪掉全选长的的数量。

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long s[105],l[105],sum[105],dp[1005][105],ans; 
int main(){
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)scanf("%lld",&s[i]);
	for(int i=1;i<=m;i++){
		scanf("%lld",&l[i]);
		sum[i]=l[i]+s[i];
	}
	dp[0][1]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=m;k++){
				dp[i][j]=(dp[i][j]+((sum[k]*sum[j]-l[k]*l[j])%1000000007)*dp[i-1][k])%1000000007;
			}
		}
	}
	for(int i=1;i<=m;i++){
		ans+=dp[n][i];
		ans%=1000000007;
	}
	printf("%lld",ans%1000000007);
	return 0;
}

时间复杂度 O(nm2)\operatorname{O}(nm^2)

矩阵优化

显然对于 E2 上面做法是过不去的。

考虑一下:每次我们转移,对于一个确定的 kk,我们在 dpi1,kdp_{i-1,k} 前乘的系数是一定的,不难联想到矩阵优化。

因为矩阵有结合律,所以我们可以使用矩阵快速幂优化。

在矩阵优化题中,最重要的就是构造转移矩阵。这个题的转移矩阵就是 dpi1,kdp_{i-1,k} 的系数,即下面的矩阵:

[sum1×sum1l1×l1sum2×sum1l2×l1summ×sum1lm×l1sum1×sum2l1×l2sum2×sum2l2×l2summ×sum2lm×l2 summ×sum1lm×l1summ×sum2lm×l2summ×summlm×lm]\begin{bmatrix}sum_1\times sum_1-l_1\times l_1 & sum_2\times sum_1-l_2\times l_1 & \cdots & sum_m\times sum_1-l_m\times l_1\\sum_1\times sum_2-l_1\times l_2 & sum_2\times sum_2-l_2\times l_2 & \cdots & sum_m\times sum_2-l_m\times l_2\\\vdots &\vdots &\ddots & \vdots\\sum_m\times sum_1-l_m\times l_1 &sum_m\times sum_2-l_m\times l_2 &\cdots &sum_m\times sum_m-l_m\times l_m\end{bmatrix}

如果不理解,可以试着去手搓下面柿子的值:

[dpi1,1dpi1,2dpi1,m]×[sum1×sum1l1×l1sum2×sum1l2×l1summ×sum1lm×l1sum1×sum2l1×l2sum2×sum2l2×l2summ×sum2lm×l2 summ×sum1lm×l1summ×sum2lm×l2summ×summlm×lm]\begin{bmatrix}dp_{i-1,1} & dp_{i-1,2} & \cdots & dp_{i-1,m}\end{bmatrix}\times\begin{bmatrix}sum_1\times sum_1-l_1\times l_1 & sum_2\times sum_1-l_2\times l_1 & \cdots & sum_m\times sum_1-l_m\times l_1\\sum_1\times sum_2-l_1\times l_2 & sum_2\times sum_2-l_2\times l_2 & \cdots & sum_m\times sum_2-l_m\times l_2\\\vdots &\vdots &\ddots & \vdots\\sum_m\times sum_1-l_m\times l_1 &sum_m\times sum_2-l_m\times l_2 &\cdots &sum_m\times sum_m-l_m\times l_m\end{bmatrix}

就会得到:

[dpi,1dpi,2dpi,m]\begin{bmatrix}dp_{i,1} & dp_{i,2} & \cdots & dp_{i,m}\end{bmatrix}

所以这个矩阵是对的。

#include<bits/stdc++.h>
using namespace std;
struct matrix{
	long long a[105][105];
};
int m;
long long n;
matrix operator *(matrix a,matrix b){
	matrix c;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=m;j++){
			c.a[i][j]=0;
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=m;k++){
				c.a[i][j]+=a.a[i][k]*b.a[k][j];
				c.a[i][j]%=1000000007;
			}
		}
	}
	return c;
}
matrix qpow(matrix a,long long b){
	matrix res;
	for(int i=1;i<=m;i++){
		res.a[1][i]=0;
	}
	res.a[1][1]=1;
	while(b){
		if(b&1)res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
long long s[105],l[105],sum[105],tot;
matrix a;
matrix ans;
int main(){
	scanf("%d%lld",&m,&n);
	for(int i=1;i<=m;i++)scanf("%lld",&s[i]);
	for(int i=1;i<=m;i++){
		scanf("%lld",&l[i]);
		sum[i]=l[i]+s[i];
	}
	for(int i=1;i<=m;++i){
		for(int j=1;j<=m;j++){
			a.a[i][j]=(sum[i]*sum[j]-l[i]*l[j])%1000000007;
		}
	} 
	ans=qpow(a,n);
	for(int i=1;i<=m;i++){
		tot=(tot+ans.a[1][i])%1000000007; 
	}
	printf("%lld",tot);
	return 0;
}
posted @   Weslie_qwq  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示