CodeForces 1105C Ayoub and Lost Array(计数DP入门)

题目链接

题目含义:

给定三个数字n ,l, r,表示有一个长度为 n 的序列,序列中每个数字都在 l 到 r 之间,问有多少种方案组合是的整个序列的和是 3 的整数倍

思路:

用一个数组 dp[i][0]表示序列中的前 i 个数字组成的所有方案中,对 3 取模为 0 的方案数,dp[i][1]、dp[i][2]以此类推

我们来考虑状态转移,dp[i][0]应该等于什么?

首先想一下怎样的组合能使得和模 3 为 0 ?

  1. dp[i - 1][0] 后面添上一个模 3 为 0 的在 l 到 r 区间内的数
  2. dp[i - 1][1] 后面添上一个模 3 为 2 的在 l 到 r 区间内的数
  3. dp[i - 1][2] 后面添上一个模 3 为 1 的在 l 到 r 区间内的数

因此得到第一个递推式

dp[i][0] = dp[i - 1][0] * num + dp[i - 1][1] * num2 + dp[i - 1][2] * num1;

 依次可以得到以下递推式

dp[i][1] = dp[i - 1][1] * num + dp[i - 1][0] * num1 + dp[i - 1][2] * num2;
dp[i][2] = dp[i - 1][2] * num + dp[i - 1][0] * num2 + dp[i - 1][1] * num1;

(递推式没有取模,题目要求取模,而且结果很大,注意取模)

接下来就是初始化问题,对于dp[1][0]来说,就是取一个数字和是 3 的倍数的方案数,显而易见就是区间内 3 的倍数的个数

dp[1][1]、dp[1][2]分别是区间内模 3 余 1 的个数和模 3 余 2 的个数

结果就是dp[n][0]( n 个数组成的和模 3 余 0 的方案数)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2 * 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
ll dp[N][4];
int cnt(int n){
	int t = n / 3;
	return t;
}
int main()
{
	int n, l, r;
	scanf("%d %d %d", &n, &l, &r);
	int num = cnt(r) - cnt(l - 1);
	int num1 = num - 1;
	if(r % 3 >= 1)num1++;
	int num2 = num - 1;
	if(r % 3 >= 2)num2++;
	if(l % 3 == 1){
		num1++;num2++;
	}
	else if(l % 3 == 2){
		num2++;
	}
	dp[1][0] = num;
	dp[1][1] = num1;
	dp[1][2] = num2;
	for (int i = 2; i <= n; i++){
		dp[i][0] = (dp[i - 1][0] * num % mod + dp[i - 1][1] * num2 % mod + dp[i - 1][2] * num1 % mod) % mod;
		dp[i][1] = (dp[i - 1][1] * num % mod + dp[i - 1][0] * num1 % mod + dp[i - 1][2] * num2 % mod) % mod;
		dp[i][2] = (dp[i - 1][2] * num % mod + dp[i - 1][0] * num2 % mod + dp[i - 1][1] * num1 % mod) % mod;
	}
	printf("%lld\n", dp[n][0]);
	return 0;
}

 

posted @ 2019-08-26 16:40  correct  阅读(125)  评论(0)    收藏  举报