高速電力線をマトリックス最適化DP

\(T1 \)ラインアップ

説明

  

グラブの夕食は、高校生活の一部であり、現在は長さのチームがあり、\(\ N-) 、(注:人と異なるサイズの距離に保ち、さまざまな状況の間の距離を維持するために、そのキューの長さは直接反映していません数人)男性と男性の間の距離は次のように知られている\(\) 男性と女性の間の距離であるBの B、女性との間の距離である\(C \) 男性Dafan時間\(D \) 女の子Dafan時間\(E \) すべての場合に必要なキュー時間の合計(長さのボディサイズの貢献ランクを無視して)、$ 10 ^ {9}への答えモジュロ7を$。

  

入力形式

ライン6つの整数(\ \ N-) \(A \) \(B \) \(C \) \(D \) \(E \)

出力

整数ライン、それが答えです。

解決

まず、我々が構築DPの練習、と考えるのは簡単です\(Fの\を) ([I] [0/1] \)\配列は、0/1の場合は最後の人、ご飯をヒットする最後の人を表し時間の、0は1つが女性である、最後の1が男性で表しています。

Gの定義\([I] [0/1] \)の合計数は、人が中である場合には最後のプログラムを表します。ハンドは、状態遷移方程式を押します:

E.PNG

しかし、我々はそれを見つけるだろう(N \)は\を非常に大きいですが、\(A \) \を(B \) \(のC \) 非常に小さいので、あなたが必要な転送するたびに\(IA \) \(IB \) \(IC \)あなたは、スクロールアレイ転送の使用を検討することができますので、それは、非常に近いです。

しかし、時間のために最適化されたスクロール配列をしませんでした。

ここでは、転送行列の乗算の代わりに、構成のみの使用\(4 * MAX(、 B、C)\) 順に伝達行列を。

のは、マトリックスの詳細な構造についてお話しましょう!

まず見(G \)\配列の(F \)\の転送配列が影響を与えたので、私たちはちょうど行列転送しない\(のF \)を、また参加している必要があります\(グラム\)転送を。

通常、最初の行列は長い道のりを構築します:

A.PNG

しかし、考慮\を(F \) \([I]は、[0/1] \)とG \([I]が[0/1] \) 4分のものを用いて転送されるので、各\(I \)ので、各ブロック内の4つの値を維持することは、4つの値を維持するために、それは次のようになります。

B.PNG

あなたが理由を説明することができるようにわかりました、\(4 * MAX(、 B、C)\) 順序を、順序が友人を意味行列の長さと幅であります

一つの目標に続いてマトリックス構造:

C.PNG

これは、ということを意味\(R&LT \)リリース\(R&LT 1 + \) 次いで単独伝達行列上に構成されたDP伝達方程式に対する。

フォーム:

D.PNG

伝達行列構成高速電力の完了後、速やかに最終回答取得\を(F [N-] [0] \) + \(F [N-] [1] \)

詳細:コードが原因毎に1〜4として実装ので、我々は使用される\(<< 2 \)位置(X 4当量)iは各行列に対応する迅速であってもよいし、各ブロックによって選択されます|コードを簡単に処理する(=運転や操作を追加します)。

#include<bits/stdc++.h>
#define ll long long
#define N 150
using namespace std;
const int mod=1e9+7;
ll n;
int a,b,c,d,e,O;
int g[N][2],f[N][2];// f[i][0/1]表示长度为i的队伍最后为男生(0)或女生(1)的答案  g[i][1/0]与f一样,不过是记录到达这个状态的方案数 
struct Matrix{
    int a[N][N];
    Matrix(){memset(a,0,sizeof(a));}
}T,qs,asd;//T为转移矩阵 qs为初始矩阵 
void mul(Matrix &CC,Matrix A,Matrix B)
{
    Matrix C;
    int i,j; 
    for(i=0;i<O;i++)
       for(j=0;j<O;j++)
          C.a[i][j]=0;
          
    for(i=0;i<O;i++)   //两个矩阵的相乘 
    for(j=0;j<O;j++)
    if(A.a[i][j])
    {
        for(int k=0;k<O;k++)
           if(B.a[j][k])
            C.a[i][k]=(1ll*A.a[i][j]*B.a[j][k]+C.a[i][k])%mod;
    }
    CC=C;
}
void Ksm(Matrix &CC,Matrix AA,ll t)  //标准快速幂 
{
    Matrix A,C;
    t--;
    A=C=AA;
    while(t)
    {
        if(t&1)
        {
            mul(C,C,A);
        }
        mul(A,A,A);
        t>>=1;
    }
    CC=C;
}
int main()
{
    int i,j;
    scanf("%lld",&n);
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
    g[0][0]=g[0][1]=1;  //初始化 
    f[0][0]=d,f[0][1]=e;   //初始化
    int o=max(a,max(b,c)); //转移所需的最小的矩阵 
    O=o<<2;//矩阵长宽
    for(i=1;i<o;i++)// 初始化第一个矩阵 
    {
        if(i>=a) (f[i][0]+=f[i-a][0])%mod,(g[i][0]+=g[i-a][0])%mod;
        if(i>=b) (f[i][0]+=f[i-b][1])%mod,(g[i][0]+=g[i-b][1])%mod,(f[i][1]+=f[i-b][0])%mod,(g[i][1]+=g[i-b][0])%mod;
        if(i>=c) (f[i][1]+=f[i-c][1])%mod,(g[i][1]+=g[i-c][1])%mod;
        f[i][0]=(1ll*g[i][0]*d+f[i][0])%mod;
        f[i][1]=(1ll*g[i][1]*e+f[i][1])%mod;
    } 
    //下面开始把我们构造的转移矩阵完善一下 
    for(i=1;i<o;i++)
    {
        for(j=0;j<4;j++)
        T.a[i<<2|j][(i-1)<<2|j]=1; //把矩阵中的1全填了再说 
    }
    T.a[(o-b)<<2][(o-1)<<2|1] = T.a[(o-b)<<2|2][(o-1)<<2|3] = T.a[(o-b)<<2|1][(o-1)<<2] = T.a[(o-b)<<2|3][(o-1)<<2|2] = 1; //把公式中的全部i-b的影响填上1 
    T.a[(o-b)<<2|2][(o-1)<<2|1] = e; T.a[(o-b)<<2|3][(o-1)<<2] = d; //把e和d填上
     //后面也在一个一个填数 
     ++T.a[(o-a)<<2][(o-1)<<2]; ++T.a[(o-a)<<2|2][(o-1)<<2|2];  
     (T.a[(o-a)<<2|2][(o-1)<<2]+=d)%mod;
     ++T.a[(o-c)<<2|1][(o-1)<<2|1]; ++T.a[(o-c)<<2|3][(o-1)<<2|3];
     (T.a[(o-c)<<2|3][(o-1)<<2|1]+=e)%mod;
     
     for(i=0;i<o;i++)  //把之前求出的初始f付给这个初始矩阵 
     {
        qs.a[0][i<<2] = f[i][0];
        qs.a[0][i<<2|1] = f[i][1];
        qs.a[0][i<<2|2] = g[i][0];
        qs.a[0][i<<2|3] = g[i][1];
     } 
     Ksm(T,T,n-o+1); mul(qs,qs,T);  //快速转移 
     printf("%d\n",(qs.a[0][(o-1)<<2]+qs.a[0][(o-1)<<2|1])%mod);  //取最后的答案 
    return 0;
} 

おすすめ

転載: www.cnblogs.com/yzxx/p/11722839.html