题目链接
留坑,明天写。
题意:
有个 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<bits/stdc++.h>
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;
}