题目链接
留坑,明天写。
有个 n n n个点的环,每个点上有一个初始权值 x i x_{i} xi。
定义每一轮调整的描述是:对于环上每一个点的权值,有 p 1 p_1 p1的概率流向顺时针方向的下一个点,有 p 2 p_2 p2的概率流向逆时针方向的下一个点,有 p 3 p_3 p3的概率停在原地。(其中 p 1 + p 2 + p 3 = 1 p_{1}+p_{2}+p_{3}=1 p1+p2+p3=1)
问 k k k轮调整之后,每个点的权值期望,答案取模998244353。
( 3 ≤ n ≤ 500 , 0 ≤ k ≤ 1 0 18 3\leq n\leq 500 ,0\leq k\leq 10^{18} 3≤n≤500,0≤k≤1018)
首先可以给出每个点进行一轮调整后的值 X i = p 1 x i − 1 + p 3 x i + p 2 x i + 1 X_{i}=p_{1}x_{i-1}+p_{3}x_{i}+p_{2}x_{i+1} Xi=p1xi−1+p3xi+p2xi+1。
就可以轻松得到解向量的转移一次的方程:
[ p 3 p 2 0 0 p 1 p 1 p 3 p 2 0 0 0 p 1 p 3 p 2 0 0 0 p 1 p 3 p 2 p 2 0 0 p 1 p 3 ] [ x 1 x 2 x 3 x 4 x 5 ] = [ X 1 X 2 X 3 X 4 X 5 ] \left[ \begin{matrix} p_{3} & p_{2} & 0 & 0 & p_{1}\\ p_{1} & p_{3} & p_{2} & 0 & 0 \\ 0 & p_{1} & p_{3} & p_{2} & 0 \\ 0 & 0 & p_{1} & p_{3} & p_{2} \\ p_{2} & 0 & 0 & p_{1} & p_{3} \end{matrix} \right] \left[ \begin{matrix} x_{1} \\ x_{2} \\ x_{3} \\ x_{4} \\ x_{5} \end{matrix} \right] =\left[ \begin{matrix} X_{1} \\ X_{2} \\ X_{3} \\ X_{4} \\ X_{5} \end{matrix} \right] ⎣⎢⎢⎢⎢⎡p3p100p2p2p3p1000p2p3p1000p2p3p1p100p2p3⎦⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎡x1x2x3x4x5⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡X1X2X3X4X5⎦⎥⎥⎥⎥⎤
那么我们的答案就是:
[ X 1 X 2 X 3 X 4 X 5 ] = [ p 3 p 2 0 0 p 1 p 1 p 3 p 2 0 0 0 p 1 p 3 p 2 0 0 0 p 1 p 3 p 2 p 2 0 0 p 1 p 3 ] k [ x 1 x 2 x 3 x 4 x 5 ] \left[ \begin{matrix} X_{1} \\ X_{2} \\ X_{3} \\ X_{4} \\ X_{5} \end{matrix} \right] =\left[ \begin{matrix} p_{3} & p_{2} & 0 & 0 & p_{1}\\ p_{1} & p_{3} & p_{2} & 0 & 0 \\ 0 & p_{1} & p_{3} & p_{2} & 0 \\ 0 & 0 & p_{1} & p_{3} & p_{2} \\ p_{2} & 0 & 0 & p_{1} & p_{3} \end{matrix} \right]^{k} \left[ \begin{matrix} x_{1} \\ x_{2} \\ x_{3} \\ x_{4} \\ x_{5} \end{matrix} \right] ⎣⎢⎢⎢⎢⎡X1X2X3X4X5⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡p3p100p2p2p3p1000p2p3p1000p2p3p1p100p2p3⎦⎥⎥⎥⎥⎤k⎣⎢⎢⎢⎢⎡x1x2x3x4x5⎦⎥⎥⎥⎥⎤
现在,它就成了一道矩阵快速幂板题了,但是 500 ∗ 500 ∗ 500 ∗ l o g 1 0 18 ≈ 8 e 9 500*500*500*log10^{18}\approx 8e9 500∗500∗500∗log1018≈8e9,时限1 s s s是过不去的。
那么就要考虑优化。
然后就涨姿势了,还有循环矩阵这么个东西。对于循环矩阵的快速幂而言,是可以优化到 o ( n 2 l o g k ) o(n^{2}logk) o(n2logk)的。
当一个矩阵的每一行都由前一行右移一列(最后一列移到第一列)得到,我们称这样的矩阵为循环矩阵。
循 环 矩 阵 + 循 环 矩 阵 = 循 环 矩 阵 循环矩阵+循环矩阵=循环矩阵 循环矩阵+循环矩阵=循环矩阵
循 环 矩 阵 × 循 环 矩 阵 = 循 环 矩 阵 循环矩阵\times 循环矩阵=循环矩阵 循环矩阵×循环矩阵=循环矩阵
一、根据循环矩阵的定义和性质,我们要存储一个循环矩阵,只要存它的第一行就行了,后面的行可以由第一行得到。
二、我们要计算得到一个循环矩阵,也只要算出它第一行是什么就行了,同样的,后面的行可以通过第一行得到。
三、而循环矩阵通过线性运算仍然为循环矩阵,那么我们思考算循环矩阵乘循环矩阵的复杂度,因为我们只要算第一行就行了,所以矩阵乘法从原来的 o ( n 3 ) o(n^{3}) o(n3)变成了 o ( n 2 ) o(n^{2}) o(n2)。
然后,我们发现这题的矩阵就是循环矩阵,所以就可以优化到 o ( n 2 l o g k ) o(n^{2}logk) o(n2logk)了。
留坑,明天再敲
#include
using namespace std;
typedef long long ll;
const ll mod=998244353;
ll fpow(ll a,ll n)
{
ll sum=1,base=a;
while(n!=0)
{
if(n%2)sum=sum*base%mod;
base=base*base%mod;
n/=2;
}
return sum;
}
ll inv(ll a)
{
return fpow(a,mod-2);
}
struct Cmatrix
{
ll mat[505];
}A;
ll len;
Cmatrix mul(Cmatrix A,Cmatrix B)
{
Cmatrix tmp;
for(ll i=0;i<len;i++)
{
tmp.mat[i]=0;
for(int j=0;j<len;j++)
{
tmp.mat[i]=(tmp.mat[i]+A.mat[j]*B.mat[(len-j+i)%len])%mod;
}
}
return tmp;
}
Cmatrix ffpow(Cmatrix A,ll n)
{
Cmatrix sum;
for(ll i=0;i<len;i++)sum.mat[i]=0;
sum.mat[0]=1;
while(n!=0)
{
if(n%2)sum=mul(sum,A);
A=mul(A,A);
n/=2;
}
return sum;
}
ll x[505],X[505];
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
len=n;
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
ll p1=a*inv(a+b+c)%mod;
ll p2=b*inv(a+b+c)%mod;
ll p3=c*inv(a+b+c)%mod;
A.mat[0]=p3;A.mat[len-1]=p1;A.mat[1]=p2;
A=ffpow(A,k);
for(ll i=0;i<len;i++)scanf("%lld",&x[i]);
for(ll i=0;i<len;i++)
{
X[i]=0;
for(ll j=0;j<len;j++)
{
X[i]=(X[i]+x[j]*A.mat[(len-i+j)%len])%mod;
}
}
for(ll i=0;i<len;i++)printf("%lld ",X[i]);
putchar('\n');
return 0;
}