题目在这里哟
思路:
很显然,我们用平常的普通暴力肯定过不了,所以考虑矩阵乘法
我们考虑从一个数列转换成另一个数列,直接在转移矩阵中填那个位置上的1就行
然后在考虑一个转移矩阵,作为两个数交换的转移矩阵,同样简单推出
因为矩阵乘法满足结合律,同时在大小相等时也满足交换律,所以就可以先将两个转移矩阵相乘
然后快速幂就行了
code:
#include<iostream>
#include<cstdio>
using namespace std;
long long a[100][100], b[100][100];
long long n, s, m, k;
long long f[100];
long long ans[100][100];
void multi()
{
long long c[100][100];
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
c[i][j]=0;
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
for(long long k=1; k<=n; k++)
c[i][j]=(c[i][j]+a[i][k]*ans[k][j]);
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
ans[i][j]=c[i][j];
}
void multi1()
{
long long c[100][100];
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
c[i][j]=0;
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
for(long long k=1; k<=n; k++)
c[i][j]=(c[i][j]+a[i][k]*a[k][j]);
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
a[i][j]=c[i][j];
}
void ksm(long long k)
{
for(long long i=1; i<=n; i++)
ans[i][i]=1;
while(k!=0)
{
if(k&1)
multi();
multi1();
k>>=1;
}
}
void multi3()
{
long long c[100][100];
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
c[i][j]=0;
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
for(long long k=1; k<=n; k++)
c[i][j]=(c[i][j]+b[i][k]*a[k][j]);
for(long long i=1; i<=n; i++)
for(long long j=1; j<=n; j++)
a[i][j]=c[i][j];
}
void multi2()
{
long long c[100][100];
for(long long j=1; j<=n; j++)
c[1][j]=0;
for(long long i=1; i<=1; i++)
for(long long j=1; j<=n; j++)
for(long long k=1; k<=n; k++)
c[i][j]=(c[i][j]+f[k]*ans[k][j]);
for(long long i=1; i<=n; i++)
f[i]=c[1][i];
}
int main()
{
scanf("%lld%lld%lld%lld", &n, &s, &m ,&k);
for(long long i=1; i<=n; i++)
scanf("%lld", &f[i]);
for(long long i=2; i<=n; i++)
a[i][i-1]=1;
a[1][n]=1;
for(long long i=1; i<=n; i++)
if(i!=s&&i!=m)
b[i][i]=1;
b[s][m]=b[m][s]=1;
multi3();
ksm(k);
multi2();
for(long long i=1; i<=n; i++)
printf("%lld ", f[i]);
return 0;
}