Codeforces
对于 Easy 部分的做法:
很容易想到统计下来每个点的位置,枚举到达的点,然后进行转移统计即可。
时间复杂度 \(O(m^2n)\)。
由于个人习惯,代码中的 \(n\) 和 \(m\) 与原题目不同。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,m,s[100005],l[100005],t[2][100005];
signed main(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>s[i];for(int i=1;i<=n;i++)cin>>l[i];t[0][1]=1;int cnt=0;for(int i=1;i<=m;i++){cnt^=1;for(int j=1;j<=n;j++)t[cnt][j]=0;for(int j=1;j<=n;j++){for(int k=1;k<=n;k++){t[cnt][k]+=((t[cnt^1][j]*s[j])%mod*s[k])%mod;t[cnt][k]%=mod;t[cnt][k]+=((t[cnt^1][j]*s[j])%mod*l[k])%mod;t[cnt][k]%=mod;t[cnt][k]+=((t[cnt^1][j]*l[j])%mod*s[k])%mod;t[cnt][k]%=mod;}}}int sum=0;for(int i=1;i<=n;i++)sum=(sum+t[cnt][i])%mod;cout<<sum;return 0;
}
对于 Medium 部分的做法:
我们不难发现上一步转移形式很固定,甚至正好是乘上某数再加起来,而且正好每次更新同时更新了所有值。
那么我们很容易想到用矩阵优化。
直接模版把上一步的内容放到矩阵中,快速幂即可。
由于个人习惯,代码中的 \(n\) 和 \(m\) 与原题目不同。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,m,s[100005],l[100005],t[2][100005];
struct MT{int n,m,c[105][105];MT(){n=m=0;memset(c,0,sizeof(c));}MT friend operator*(MT a,MT b){MT c;c.n=a.n,c.m=b.m;for(int i=1;i<=a.n;i++){for(int j=1;j<=b.m;j++){for(int k=1;k<=a.m;k++){c.c[i][j]+=(a.c[i][k]*b.c[k][j])%mod;c.c[i][j]%=mod;}}}return c;}
}base,be;
void ksm(MT a,int b){while(b){if(b&1)be=be*a;a=a*a;b>>=1;}
}
signed main(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>s[i];for(int i=1;i<=n;i++)cin>>l[i];be.n=1,be.m=n;be.c[1][1]=1;base.n=base.m=n;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){base.c[i][j]=((s[i]*s[j]%mod+s[i]*l[j]%mod)%mod+l[i]*s[j]%mod)%mod;}}ksm(base,m);int sum=0;for(int i=1;i<=n;i++)sum=(sum+be.c[1][i])%mod;cout<<sum;return 0;
}
对于 Hard 部分的做法:
这里应该才是最难的一步,可以直接将绿题变成紫题。
我们发现矩阵里如果存下所有点的数字,那么矩阵乘法做一次就超时了。
但是这 \(n\) 又非常大,也不好直接推导数学做法。
这时候我们想到在第一个点出来以后,我们走到湖中间上时去哪里只受到前面走了什么路的影响。
那么此时有多少种可能的做法就固定了。
走到下一个屋子,还要再回来,那么此时的点也确定了。
我们将这两步放到一起,从湖中间出发再走回来,在矩阵中记录上次走长路和短路的总方案数,这样就可以用矩阵快速求解了。
我们只需要先走到中间,再矩阵求方案数,再枚举回来的点,就可以得到答案了。
关于矩阵的具体推算可以看代码。
由于个人习惯,代码中的 \(n\) 和 \(m\) 与原题目不同。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,m,s[100005],l[100005];
struct MT{int c[5][5],n,m;MT(){n=m=0;memset(c,0,sizeof(c));}MT friend operator*(MT a,MT b){MT c;c.n=a.n,c.m=b.m;for(int i=1;i<=a.n;i++){for(int j=1;j<=b.m;j++){for(int k=1;k<=a.m;k++)c.c[i][j]=(c.c[i][j]+(a.c[i][k]*b.c[k][j])%mod)%mod;}}return c;}
}base,be;
void ksm(MT a,int b){while(b){if(b&1)be=be*a;a=a*a;b>>=1;}
}
signed main(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>s[i];for(int i=1;i<=n;i++)cin>>l[i];be.n=1,be.m=2;be.c[1][1]=s[1],be.c[1][2]=l[1];base.n=base.m=2;int sum=0;for(int i=1;i<=n;i++)sum=(sum+((l[i]*s[i])%mod+(s[i]*s[i])%mod)%mod)%mod;base.c[1][1]=sum;sum=0;for(int i=1;i<=n;i++)sum=(sum+(s[i]*s[i])%mod)%mod;base.c[2][1]=sum;sum=0;for(int i=1;i<=n;i++)sum=(sum+((l[i]*s[i])%mod+(l[i]*l[i])%mod)%mod)%mod;base.c[1][2]=sum;sum=0;for(int i=1;i<=n;i++)sum=(sum+(s[i]*l[i])%mod)%mod;base.c[2][2]=sum;ksm(base,m-1);sum=0;for(int i=1;i<=n;i++){sum+=(s[i]*be.c[1][1])%mod;sum%=mod;sum+=(l[i]*be.c[1][1])%mod;sum%=mod;sum+=(s[i]*be.c[1][2])%mod;sum%=mod;}cout<<sum;return 0;
}
/*
s->s
s l s
s s s
l->s
l s s
s->l
s l l
s s l
l->l
l s l
*/