codeforces 1105c Ayoub and Lost Array 利用余数进行dp或者是递推???

题目链接https://codeforces.com/contest/1105/problem/C

题意:从l​l​到r​r​中选n​n​个数,允许相同。要使最终这n​n​个数的和是3​3​的倍数,求有多少个方案,答案mod​mod​ 109+7​109+7​。(若没有方案,输出0​0​)

这题首先很难看出来是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;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/88251466