题意:
在区间【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的转移方程容易想到矩阵快速幂优化:
代码:
#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;
}