[蓝桥杯 2014 省 A] 波动数列

一、题目描述

P8614 [蓝桥杯 2014 省 A] 波动数列

二、问题简析

设第一个数为 x 0 x_0 x0 d i = a   o r   − b d_i=a~or~-b di=a or b,则长度为 n n n 的数列的和为:

s = x 0 + x 1 + x 2 + . . . + x n − 1 = ( x 0 + 0 ) + ( x 0 + d 1 ) + ( x 0 + d 1 + d 2 ) + . . . + ( x 0 + d 1 + . . . + d n − 1 ) = n ∗ x 0 + 0 + ( n − 1 ) ∗ d 1 + ( n − 2 ) ∗ d 2 + . . . + d n − 1 \begin{split} s&=x_0+x_1+x_2+...+x_{n-1}\\ &=(x_0 + 0) + (x_0+d_1) + (x_0+d_1+d_2)+...+(x_0+d_1+...+d_{n-1})\\ &=n*x_0+0+(n-1)*d_1+(n-2)*d_2+...+d_{n-1} \end{split} s=x0+x1+x2+...+xn1=(x0+0)+(x0+d1)+(x0+d1+d2)+...+(x0+d1+...+dn1)=nx0+0+(n1)d1+(n2)d2+...+dn1

z i = 0 + ( n − 1 ) ∗ d 1 + ( n − 2 ) ∗ d 2 + . . . + ( n − i ) ∗ d i z_{i}=0+(n-1)*d_1+(n-2)*d_2+...+(n-i)*d_i zi=0+(n1)d1+(n2)d2+...+(ni)di,则 s = n ∗ x 0 + z n − 1 s=n*x_0+z_{n-1} s=nx0+zn1

∵ s = n ∗ x 0 + z n − 1 ∴ x 0 = s − z n − 1 n ∈ Z ∴ s − z n − 1 ≡ 0   ( mod  n ) 即 s ≡ z n − 1   ( mod  n ) \begin{split} &\because s = n * x_0 + z_{n-1} \\ &\therefore x_0=\frac{s-z_{n-1}}{n} \in \mathbb{Z} \\ &\therefore s-z_{n-1} \equiv 0~(\text{mod}~n) \\ &即 s \equiv z_{n-1}~(\text{mod}~n) \end{split} s=nx0+zn1x0=nszn1Zszn10 (mod n)szn1 (mod n)

d p [ i ] [ j ] = dp[i][j]= dp[i][j]= 使 j ≡ z i ( mod  n ) j\equiv z_i(\text{mod}~n) jzi(mod n) 的方案数,则

z i = z i − 1 + ( n − i ) ∗ d i z i − 1 = z i − ( n − i ) ∗ d i z i − 1 ≡ z i − ( n − i ) ∗ d i   ( mod  n ) \begin{split} z_i&=z_{i-1}+(n-i)*d_i\\ z_{i-1}&=z_i-(n-i)*d_i\\ z_{i-1} &\equiv z_i-(n-i)*d_i~(\text{mod}~n) \end{split} zizi1zi1=zi1+(ni)di=zi(ni)dizi(ni)di (mod n)

d i d_i di 可能的值为 a a a − b -b b

z i − 1 ≡ { z i − ( n − i ) ∗ a z i + ( n − i ) ∗ b   ( mod  n ) z_{i-1}\equiv \begin{cases} z_i-(n-i)*a\\ z_i+(n-i)*b \end{cases} ~(\text{mod}~n) zi1{zi(ni)azi+(ni)b (mod n)

至此,我们可以写出递归方程

d p [ i ] [ j   ( mod  n ) ] = d p [ i ] [ z i   ( mod  n ) ] = d p [ i − 1 ] [ z i − 1   ( mod  n ) ]   / /  包含两种情况 = d p [ i − 1 ] [ z i − ( n − i ) ∗ a   ( mod  n ) ] + d p [ i − 1 ] [ z i + ( n − i ) ∗ b   ( mod  n ) ] \begin{split} dp[i][j~(\text{mod}~n)] &= dp[i][z_i~(\text{mod}~n)] \\ &=dp[i-1][z_{i-1}~(\text{mod}~n)]~//~包含两种情况\\ &=dp[i-1][z_i-(n-i)*a~(\text{mod}~n)]+dp[i-1][z_i+(n-i)*b~(\text{mod}~n)] \end{split} dp[i][j (mod n)]=dp[i][zi (mod n)]=dp[i1][zi1 (mod n)] // 包含两种情况=dp[i1][zi(ni)a (mod n)]+dp[i1][zi+(ni)b (mod n)]

注:

  • 1、取模运算可能会产生负数,而数组肯定不能通过负数访问,所以要转化成正数:(x % n + n) % n
  • 2、dp[0][0]=1:因为 z 0 = 0 z_0=0 z0=0,算一种情况。

三、AC代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int quickin(void)
{
	int ret = 0;
	bool flag = false;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')    flag = true;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9' && ch != EOF)
	{
		ret = ret * 10 + ch - '0';
		ch = getchar();
	}
	if (flag)    ret = -ret;
	return ret;
}

const int MOD = 1e8 + 7;
ll n, s, a, b, dp[1003][1003];

int get_mod(ll x)
{
	return (x % n + n) % n; 
} 

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	cin >> n >> s >> a >> b;
	dp[0][0] = 1;
	for (int i = 1; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			dp[i][j] = (dp[i - 1][get_mod(j - (n - i) * a)] + dp[i - 1][get_mod(j + (n - i) * b)]) % MOD;
		}
	}
	
	cout << dp[n - 1][get_mod(s)] << endl;
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值