Examples
Input
2 1 3
Output
3
Input
3 2 2
Output
1
Input
9 9 99
Output
711426616
Note
In the first example, the possible arrays are : [1,2], [2,1], [3, 3].
In the second example, the only possible array is [2, 2, 2].
题目链接:https://codeforces.com/problemset/problem/1105/C
题意:有一个数组,元素个数n,元素取值区间为[l,r],n个值相加可整除3,问这样的数组的数目(注明: [1,2],[2,1]这两个属于不同的数组)输出的结果(1e9+7)取模。
题解:采用DP求解
DP数组:dp[n][3]
dp[i][0]表示 该数组元素个数为i,元素和对3取模为0,这种的数组有dp[i][0]种;
dp[i][1]表示 该数组元素个数为i,元素和对3取模为1,这种的数组有dp[i][1]种;
dp[i][2]表示 该数组元素个数为i,元素和对3取模为2,这种的数组有dp[i][2]种;
元素和可整除3,元素对3取模结果有:0,1,2;
我们先算出从l到r数据范围中取模结果为0,1,2的个数,设为:a0,a1,a2;
当前的状态与前一个的状态有关—>写成状态转移方程
状态转移方法为:若当前有i个数,那么取模为0的个数应为(i-1)个数中,i-1个元素取模为0的数量 × 区间内取模为0的数量(就是i-1个元素取模为0,再选一个区间内的取模为0的元素,组合构成i个元素取模为0)+ i-1个元素取模为1的数量 × 区间内取模为2的数量 (就是i-1个元素取模为1,再选一个区间内的取模为2的元素,组合构成i个元素使取模为0) + i-1个元素取模为2的数量 × 区间内取模为1的数量 (就是i-1个元素取模为2,再选一个区间内的取模为1的元素,组合构成i个元素使取模为0)。同理取模为1、2的方法同上。
状态转移方程为:
dp[i][0]=dp[i-1][0]*a0+dp[i-1][1]*a2+dp[i-1][2]*a1;
dp[i][1]=dp[i-1][0]*a1+dp[i-1][1]*a0+dp[i-1][2]*a2;
dp[i][2]=dp[i-1][0]*a0+dp[i-1][1]*a2+dp[i-1][2]*a1;
现在还有一个问题:就是区间内余数为0,1,2的个数a0,a1,a2。
因为是模3的循环节,所以有:
a0=r/3-(l-1)/3; ;区间内模3余0个数
a1=(r+2)/3-(l+1)/3; ;区间内模3余1个数
a2=(r+1)/3-l/3; ;区间内模3余2个数
附AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int MAXN=2e5+10;
const int mod=1e9+7;
ll dp[MAXN][3];
ll n,l,r,a0,a1,a2;
int main()
{
cin>>n>>l>>r;
a0=r/3-(l-1)/3,a1=(r+2)/3-(l+1)/3,a2=(r+1)/3-l/3;
dp[1][0]=a0,dp[1][1]=a1,dp[1][2]=a2;
for(int i=2;i<=n;i++)
{
dp[i][0]=(dp[i-1][0]*a0%mod+dp[i-1][1]*a2%mod+dp[i-1][2]*a1%mod)%mod;
dp[i][1]=(dp[i-1][0]*a1%mod+dp[i-1][1]*a0%mod+dp[i-1][2]*a2%mod)%mod;
dp[i][2]=(dp[i-1][0]*a2%mod+dp[i-1][1]*a1%mod+dp[i-1][2]*a0%mod)%mod;
}
cout<<dp[n][0]<<endl;
return 0;
}