\(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] \)の合計数は、人が中である場合には最後のプログラムを表します。ハンドは、状態遷移方程式を押します:
しかし、我々はそれを見つけるだろう(N \)は\を非常に大きいですが、\(A \) 、\を(B \) 、\(のC \) 、非常に小さいので、あなたが必要な転送するたびに\(IA \) 、\(IB \) 、\(IC \)あなたは、スクロールアレイ転送の使用を検討することができますので、それは、非常に近いです。
しかし、時間のために最適化されたスクロール配列をしませんでした。
ここでは、転送行列の乗算の代わりに、構成のみの使用\(4 * MAX(、 B、C)\) 順に伝達行列を。
のは、マトリックスの詳細な構造についてお話しましょう!!
まず見(G \)\配列の(F \)\の転送配列が影響を与えたので、私たちはちょうど行列転送しない\(のF \)を、また参加している必要があります\(グラム\)転送を。
通常、最初の行列は長い道のりを構築します:
しかし、考慮\を(F \) \([I]は、[0/1] \)とG \([I]が[0/1] \) 4分のものを用いて転送されるので、各\(I \)ので、各ブロック内の4つの値を維持することは、4つの値を維持するために、それは次のようになります。
あなたが理由を説明することができるようにわかりました、\(4 * MAX(、 B、C)\) 順序を、順序が友人を意味行列の長さと幅であります
一つの目標に続いてマトリックス構造:
これは、ということを意味\(R&LT \)リリース\(R&LT 1 + \) 、次いで単独伝達行列上に構成されたDP伝達方程式に対する。
フォーム:
伝達行列構成高速電力の完了後、速やかに最終回答取得\を(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;
}