Codeforeces #420 E. Okabe and El Psy Kongroo 遞推加矩陣快速冪

比較好的一道題,首先是是遞推,遞推很容易想到,我們假設dp[i][j]表示走到i,j的方案數 那麼其實就是求出每一段a[i]-b[i]的值 就可以得出來了

可以得到

dp[i][j+1] += dp[i-1][j]; j+1<=ci

dp[i][j-1] += dp[i-1][j];  j-1>=0

dp[i][j] += dp[i-1][j];

因爲i的範圍很大,看了解法後知道要用矩陣快速冪

我們構造一個16*16的矩陣 矩陣mat[i][j] 表示從y軸的i點走到y軸的j點的方案數,當長度爲一的時候這個矩陣很好構造 那麼長度爲2的時候其實就是mat^2,那麼直接快速冪求出長度爲b[i]-a[i],然後每一段的方案知道後這個題就基本解決了 詳細看代碼

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>

using namespace std;
#define LL long long
#define N 18
#define MOD 1000000007ll
struct Matrix{
    LL dat[N][N];
    int n;
    Matrix(){
        _init();
    }
    void _init(){
        memset(dat,0,sizeof(dat));
    }
    LL* const operator[](int i)
    {
		return dat[i];
    }
	const LL*  operator[](int i)const
	{
		return dat[i];
	}
    void operator%(LL mod)
    {
        for(int i = 0;i<n;i++)
        {
            for(int j = 0;j<n;j++)
            {
                dat[i][j]%=mod;
            }
        }
    }
    Matrix operator *(const Matrix& mat){
        Matrix temp;
        temp.n = mat.n;
        for(int i = 0;i<n;i++)
        {
            for(int j = 0;j<n;j++)
            {
                for(int k = 0;k<n;k++)
                {
                   temp[i][j] += dat[i][k]*mat[k][j];
                   temp[i][j]%=1000000007ll;
                }
            }
        }
        return temp;
    }
};
Matrix ans,sta;
void quickPow(LL len)
{
    while(len)
    {
        if(len&1)
        {
            ans = ans*sta;
            ans%MOD;
        }
        len >>= 1;
        sta = sta*sta;
        sta%MOD;
    }
}
int main()
{
    LL n,k;
    while(scanf("%lld%lld",&n,&k)!=EOF)
    {
        LL a[105],b[105],c[105];
        for(int i = 0;i<n;i++)
        {
            scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
        }
        ans._init();
        ans.n = 16;
        sta.n = 16;
        for(int i = 0;i<=ans.n;i++)
        {
            ans[i][i] = 1;
        }
        sta._init();

        for(int i = 0;i<n;i++)
        {
            sta._init();
            for(int j = 0;j<=c[i];j++)
            {
                if(j+1<=c[i])
                    sta[j][j+1]++;
                if(j-1>=0)
                    sta[j][j-1]++;
                sta[j][j]++;
            }
            if(b[i]>k)
            {
                quickPow(k-a[i]);
            }
            else quickPow(b[i]-a[i]);
        }

        printf("%lld\n",ans[0][0]);
    }
	return 0;
}


發佈了36 篇原創文章 · 獲贊 1 · 訪問量 7740
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章