列のシミュレーションゲームチノ番号

行列加速再発

Nの範囲がkの広い範囲は、我々は、nから出発し考えることができ、比較的小さいです。

1.まず、任意の行列*行列が変更されないことを知っています。

だから、交換作業のために、私たちは、このような行列を作成することができます。

S、M行の添加は、他のすべての行がF [i]は[I] = 1。

Sライン:F [S] [M] = 1; m行目:F [M] [S] = 1。

その後、我々は交換作業を完了しました。

左シフト演算2.、私たちは、このような行列を作成することができます。

[I] [I + 1] 1 = F n行目に加えて、他のすべての行があります。

N行目:F [N] [1] = 1。

3.我々の初期行列F [i]は、[1] = [I]。

法律に沿って結合マトリックスので、私たちは同様の急速な電源方式をスピードアップすることができます。

そして、それができる、時間の複雑性O(\(N- ^ 3 \タイムズログ(K)\) )。

私は長いと臭いのコードを提供します

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long long n,s,m,k;
struct jz
{
    long long c[85][85];
}f,base,lin1,lin2;
jz operator * (const jz &a,const jz &b)//矩阵重载乘号 
{
    jz lin;
    for(int i=1;i<=80;++i)
    {
        for(int j=1;j<=80;++j)
        {
            lin.c[i][j]=0;
            for(int k=1;k<=80;++k)
            {
                lin.c[i][j]+=(a.c[k][j]*b.c[i][k]);
            }
        }
    }
    return lin;
}
jz ksm(jz a,long long b)
{
    jz anss;
    memset(anss.c,0,sizeof(anss.c));
    for(int i=1;i<=n;++i)anss.c[i][i]=1;
    for(;b;b>>=1,a=a*a)
    {
        if(b&1)
        anss=a*anss;
    }
    return anss;
}
void dy(jz x)//调试用的,可以忽略
{
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
        cout<<x.c[i][j]<<" ";
        cout<<endl;
    }
}
int main()
{
    cin>>n>>m>>s>>k;
    for(int i=1;i<=n;++i)scanf("%lld",&f.c[i][1]);
    for(int i=1;i<=n;++i)if(i!=s&&i!=m)lin1.c[i][i]=1;
    lin1.c[s][m]=lin1.c[m][s]=1;
    for(int i=1;i<=n-1;++i)lin2.c[i][i+1]=1;
    lin2.c[n][1]=1;
    base=lin1*lin2;
    base=ksm(base,k);
    f=f*base;
    for(int i=1;i<=n;++i)printf("%lld ",f.c[i][1]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/wljss/p/11496674.html