Codeforces Round #533 (Div. 2)---C:Ayoub and Lost Array(动态规划到矩阵快速幂)

题意:

在区间【l,r】内选n个数,使得 n 个数的和是 3 的倍数,求有多少种选法

分析:

考虑 dp[n][m],表示在【l,r】内选 n 个数,他们的和模 3 余数为m的选法数量

有如下转移方程:(m0,m1,m2分别为【l,r】内模3余数为0,1,2的数量)

dp[n][0] = dp[n-1][0] * m0 + dp[n-1][1] * m2 + dp[n-1][2] * m1

dp[n][1] = dp[n-1][0] * m1 + dp[n-1][1] * m0 + dp[n-1][2] * m2

dp[n][2] = dp[n-1][0] * m2 + dp[n-1][1] * m1 + dp[n-1][2] * m0

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int MAXN = 2e5+55;
LL dp[MAXN][3],m0,m1,m2,l,r,n;
void cal()                       //计算m0,m1,m2
{
    LL len = r - l + 1;
    m0 = len / 3;
    m1 = len / 3;
    m2 = len / 3;
    if(l % 3 == 0)
    {
        if(len % 3 == 1) m0++;
        if(len % 3 == 2) m0++,m1++;
    }
    else if(l % 3 ==1)
    {
        if(len % 3 == 1) m1++;
        if(len % 3 == 2) m1++,m2++;
    }
    else
    {
        if(len % 3 == 1) m2++;
        if(len % 3 == 2) m2++,m0++;
    }
}
int main()
{
    cin>>n>>l>>r;cal();
    dp[1][0] = m0;
    dp[1][1] = m1;
    dp[1][2] = m2;
    for(int i=2;i<=n;++i)
    {
        dp[i][0] = (dp[i-1][0]*m0 + dp[i-1][1]*m2 + dp[i-1][2]*m1)%MOD;
        dp[i][1] = (dp[i-1][0]*m1 + dp[i-1][1]*m0 + dp[i-1][2]*m2)%MOD;
        dp[i][2] = (dp[i-1][0]*m2 + dp[i-1][1]*m1 + dp[i-1][2]*m0)%MOD;
    }
    cout<<dp[n][0];
    return 0;
}

 从dp的转移方程容易想到矩阵快速幂优化:

\begin{pmatrix} m_0& m_2 &m_1 \\ m_1&m_0 &m_2 \\ m_2&m_1 &m_0 \end{pmatrix}*\begin{pmatrix} F[n-1][0]\\F[n-1][1] \\ F[n-1][2] \end{pmatrix}=\begin{pmatrix} F[n][0]\\F[n][1] \\ F[n][2] \end{pmatrix}

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
LL a[3][3],b[3][1];
LL m0,m1,m2,n,l,r;
void cal()
{
    LL len = r - l + 1;
    m0 = len / 3;
    m1 = len / 3;
    m2 = len / 3;
    if(l % 3 == 0)
    {
        if(len % 3 == 1) m0++;
        if(len % 3 == 2) m0++,m1++;
    }
    else if(l % 3 ==1)
    {
        if(len % 3 == 1) m1++;
        if(len % 3 == 2) m1++,m2++;
    }
    else
    {
        if(len % 3 == 1) m2++;
        if(len % 3 == 2) m2++,m0++;
    }
}
void init()
{
    cal();
    a[0][0] = m0,a[0][1] = m2,a[0][2] = m1;
    a[1][0] = m1,a[1][1] = m0,a[1][2] = m2;
    a[2][0] = m2,a[2][1] = m1,a[2][2] = m0;
    b[0][0] = m0,b[1][0] = m1,b[2][0] = m2;
}
void cal_matrix1()
{
    LL t[3][1] = {0};
    for(int i = 0; i < 3; ++i)
        for(int j = 0; j < 3; ++j)
             t[i][0] = (t[i][0] + a[i][j]*b[j][0]) % MOD;
    memcpy(b,t,sizeof(t));
}
void cal_matrix2()
{
    LL t[3][3] = {0};
    for(int i = 0; i < 3; ++i)
        for(int j = 0; j < 3; ++j)
            for(int k = 0; k < 3; ++k)
                t[i][j] = (t[i][j] + a[i][k]*a[k][j]) % MOD;
    memcpy(a,t,sizeof(t));
}
LL solve()
{
    init();
    int x = n - 1;
    while(x)
    {
        if(x & 1) cal_matrix1();
        cal_matrix2();
        x >>= 1;
    }
    return b[0][0] % MOD;
}
int main()
{
   cin>>n>>l>>r;
   cout<<solve();
   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/86570047