题目链接https://codeforces.com/contest/1105/problem/C
题意:从ll到rr中选nn个数,允许相同。要使最终这nn个数的和是33的倍数,求有多少个方案,答案modmod 109+7109+7。(若没有方案,输出00)
这题首先很难看出来是DP--QAQ,反正我是看不出来,然后看的题解才知道,可以用DP的;
首先你需要这样去思考这样一个问题:
要求的序列是可以被3整除的,那么余数就是有三种情况:0 ,1 ,2
然后依据这样的特点,你需要dp[i][j]--代表前i个元素组成的序列,余数为j的组合数情况;
一开始我们需要求出这个[L,R]范围内有多少可以被3相除,然后余数为0,1,2的个数 ,然后去初始化dp[1][0]、dp[1][1]、dp[1][2]
那么剩下的就是dp的表达式了,,,,,这个的话具体看一下代码吧,emmmmm,我还是讲一下dp[i][1]吧,其他的依次类推
设a、b、c分别是[L,R]区间里面余数为0,1,2的元素个数,那么就可以这样去写:
dp[i][1]=((dp[i-1][0]*b%MOD+dp[i-1][1]*a%MOD)%MOD+dp[i-1][2]*c%MOD)%MOD;
为啥这样去写呢,你可以这样去理解dp[i][1]是前i宽度的序列余数为1的组合数,那么就可以前面推出来:
dp[i-1][0]*b--余数为0和余数为1的组合数,那么余数就是1
dp[i-1][1]*a--余数为1和余数为0的组合数,那么余数就是1
dp[i-1][2]*c--余数为2和余数为2的组合数,那么余数就是1(2+2%3)
那么剩下的就是依次类推就能得到结果了
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
using namespace std;
const int N=2e5+100;
typedef long long ll;
const int INF=0x3f3f3f3f;
const ll MOD=1e9+7;
ll dp[N][3];
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int n;
ll L,R;
scanf("%d%lld%lld",&n,&L,&R) ;
ll a,b,c;
a=b=c=(R-L+1)/3;
for(int i=0;i<(R-L+1)%3;i++){
if((i+L)%3==0) a++;
if((i+L)%3==1) b++;
if((i+L)%3==2) c++;
}
dp[1][0]=a;dp[1][1]=b;dp[1][2]=c;
for(int i=2;i<=n;i++){
dp[i][0]=((dp[i-1][0]*a%MOD+dp[i-1][1]*c%MOD)%MOD+dp[i-1][2]*b%MOD)%MOD;
dp[i][1]=((dp[i-1][0]*b%MOD+dp[i-1][1]*a%MOD)%MOD+dp[i-1][2]*c%MOD)%MOD;
dp[i][2]=((dp[i-1][0]*c%MOD+dp[i-1][1]*b%MOD)%MOD+dp[i-1][2]*a%MOD)%MOD;
}
printf("%lld\n",dp[n][0]);
return 0;
}