【洛谷】P8614 [蓝桥杯 2014 省 A] 波动数列 的题解

【洛谷】P8614 [蓝桥杯 2014 省 A] 波动数列 的题解

题目传送门

思路

对于第 i i i 项, i > 1 i>1 i>1,我们都可以对第 i − 1 i-1 i1 项进行 + a +a +a − b -b b 操作得到第 i i i 项,最终 n n n 个数的和要等于 s s s
我们不妨将对每一项的操作表示为 o p op op o p op op 有可以表示 + a +a +a 操作也可以表示 − b -b b 操作, o p [ i ] op[i] op[i] 表示第 i + 1 i+1 i+1 项进行的操作。

设首项即第 1 1 1 项为 x x x,我们能够构造出的全部情况就是 s s = n × x + k × a − t × b ss = n \times x + k \times a - t \times b ss=n×x+k×at×b,其中, s s ss ss 表示我们构造的数列和。

k + t = 1 + 2 + … … + ( n − 1 ) = n × 2 k+t = 1 + 2 + …… + (n-1) = n \times 2 k+t=1+2+……+(n1)=n×2

而我们要做的就是找到 s s = s ss = s ss=s 的方案数。

我们还可以发现对第 i i i 项进行操作时,它对整个数列之和的贡献为 o p × ( n − i + 1 ) op \times (n-i+1) op×(ni+1),若 o p = − b op=-b op=b,则贡献为 ( − b ) × ( n − i + 1 ) (-b) \times (n-i+1) (b)×(ni+1),若 o p = a op=a op=a,则贡献为 a × ( n − i + 1 ) a \times (n-i+1) a×(ni+1)

使用动态规划,dp[i][j] 表示前 i i i 个数中,和值为 j j j 的组合数。
递推关系,dp[i][j] = dp[i - 1][j] + dp[i - 1][j - i]
(由于规模较大,代码中我们使用滚动数组)

接下来我们的思路就变成了,枚举全部的 k k k,判断这种情况下是否满足上面的“整除关系”,若满足,我们就让答案加上枚举到的 k k k 所包含的方案数。

代码

#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO {
	inline int read() {
		register int x = 0, f = 1;
		register char c = getchar();
		while (c < '0' || c > '9') {
			if(c == '-') f = -1;
			c = getchar();
		}
		while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
		return x * f;
	}
	inline void write(int x) {
		if(x < 0) putchar('-'), x = -x;
		if(x > 9) write(x / 10);
		putchar(x % 10 + '0');
		return;
	}
}
using namespace fastIO;
const ll MOD = 100000007;
ll dp[1000005] = {1LL};
ll ans, s, a, b;
int n;
int main() {
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n = read();
	scanf("%lld%lld%lld", &s, &a, &b);
	for(int i = 1; i < n; i ++) {
		for(int j = i * (i + 1) / 2; j >= i ;j --) {
			dp[j] = (dp[j] + dp[j-i]) % MOD;
		} 
	}		
	int m = n * (n - 1) / 2;  
	int c = a + b;
	ll ss = s - m * b; 
	for(int i = 0; i <= m; i ++) {
		if(ss % n == 0) {
			ans = (ans + dp[i]) % MOD;
		}
		ss += c;
	}
	printf("%lld\n", ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值