Codeforces#533 C.Ayoub and Lost Array(組合數學&遞推)

問題

Ayoub had an array a of integers of size n and this array had two interesting properties:

  1. All the integers in the array were between l and r (inclusive).
  2. The sum of all the elements was divisible by 3.

Unfortunately, Ayoub has lost his array, but he remembers the size of the array n and the numbers l and r, so he asked you to find the number of ways to restore the array.

Since the answer could be very large, print it modulo 109+7(i.e. the remainder when dividing by 109+7). In case there are no satisfying arrays (Ayoub has a wrong memory), print 0.

輸入

The first and only line contains three integers n, l and r (1≤n≤2⋅1e5,1≤l≤r≤1e9) — the size of the lost array and the range of numbers in the array.

輸出
Print the remainder when dividing by 109+7 the number of ways to restore the array.

樣例
input
2 1 3
output
3
input
3 2 2
output
1
input
9 9 99
output
711426616
註釋
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].

分析
題意是在l~r的區間內找任意k個數,這些數相加正好是3的倍數,問有幾種這樣的k個數。就是有多少種這樣的組合。
因爲是求和是3的倍數,這裏先推一下和是3的倍數的數都是有哪些數組成。當k=1時,只有l~~r內餘數爲0的數組成,假如這種數有num0個;即dp[0][1] = num0;當k=2時,可以用兩個在l~~r餘數爲0的數進行組合,即dp[0][1]*num0種;也可以用一個在l~~r餘數爲1的數(假如這種數有num1個,即dp[1][1] = num1)和一個在l~~r餘數爲2的數(假如這種數有num2個,即dp[2][1] = num2)進行組合,即dp[1][1] *num2種;也可以用一個在l~~r餘數爲2的數和一個在l~~r餘數爲1的數進行組合,即dp[2][1]*num1種,所以dp[0][2] = dp[0][1] *num0+dp[1][1]*num2+dp[2][1]*num1種。同理可以證出來dp[1][2],dp[2][2];以此類推
dp[0][i] = dp[0][i-1]*num0+dp[1][i-1]*num2+dp[2][i-1]*num1;
dp[1][i] = dp[0][i-1]*num1+dp[1][i-1]*num0+dp[2][i-1]*num2;
dp[2][i] = dp[0][i-1]*num2+dp[0][i-1]*num2+dp[1][i-1]*num1;
最終dp[0][k]即是任意k個數組成的和是3的倍數的種類數。

#include<iostream>
using namespace std;
const long long mod = 1e9 + 7;
long long dp[3][200200];
int main()
{
	long long n, l, r;
	cin >> n >> l >> r;
	for (int i = 0; i < 3; i++)
	{
		dp[i][0] = 0;
		dp[i][1] = r / 3;
		dp[i][1] -= (l - 1) / 3;
	}
	switch (r % 3)
	{
	case 1: dp[1][1]++; break;
	case 2: dp[2][1]++; dp[1][1]++; break;
	default:break;
	}
	switch ((l - 1) % 3)
	{
	case 1: dp[1][1]--; break;
	case 2: dp[2][1]--; dp[1][1]--; break;
	default:break;
	}
	//以上爲求num0,num1,num2。下面爲公式遞推。
	for (int i = 2; i <= n; i++)
	{
		dp[0][i] = ((dp[1][i - 1] * dp[2][1]) % mod + (dp[0][i - 1] * dp[0][1]) % mod + (dp[2][i - 1] * dp[1][1]) % mod) % mod;
		dp[1][i] = ((dp[0][i - 1] * dp[1][1]) % mod + (dp[2][i - 1] * dp[2][1]) % mod + (dp[1][i - 1] * dp[0][1]) % mod) % mod;
		dp[2][i] = ((dp[0][i - 1] * dp[2][1]) % mod + (dp[1][i - 1] * dp[1][1]) % mod + (dp[2][i - 1] * dp[0][1]) % mod) % mod;
	}
	cout << dp[0][n] << endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章