1214. 波动数列

题目链接

1214. 波动数列

观察这个数列:

1 3 0 2 -1 1 -2 …

这个数列中后一项总是比前一项增加2或者减少3,且每一项都为整数。

栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 b 的整数数列可能有多少种呢?

输入格式

共一行,包含四个整数 \(n,s,a,b\),含义如前面所述。

输出格式

共一行,包含一个整数,表示满足条件的方案数。

由于这个数很大,请输出方案数除以 \(100000007\) 的余数。

数据范围

\(1≤n≤1000,\)
\(−10^9≤s≤10^9,\)
\(1≤a,b≤10^6\)

输入样例:

4 10 2 3

输出样例:

2

样例解释

两个满足条件的数列分别是2 4 1 3和7 4 1 -2。

解题思路

dp

设初始值为 \(x\)\(d_i\)\(a\)\(-b\),则序列和为 \(nx+(n-1)d_1+(n-2)d_2+\dots +d_{n-1}=s\),则:\(x=\frac{s-((n-1)d_1+(n-2)d_2+\dots +d_{n-1})}{n}\),由于 \(x\) 为任意整数,所以 \(s\equiv (n-1)d_1+(n-2)d_2+\dots +d_{n-1}\bmod n\),然后进行dp:

  • 状态表示:\(f[i][j]\)\(i\) 个数余数为 \(j\) 的方案数

  • 状态计算:\(f[i][j]=(f[i-1][((j-(n-i)*a)%n+n)%n]+f[i-1][((j+(n-i)*b)%n+n)%n])%mod\)
    分析:即第 \(i\) 个数选 \(a\) 还是 \(-b\)

  • 时间复杂度:\(O(n^2)\)

代码

// Problem: 波动数列
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1216/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1005,mod=1e8+7;
int a,b,s,n,f[N][N];
int main()
{
	cin>>n>>s>>a>>b;
    f[0][0]=1;
    for(int i=1;i<n;i++)
    	for(int j=0;j<n;j++)
    		f[i][j]=(f[i-1][((j-(n-i)*a)%n+n)%n]+f[i-1][((j+(n-i)*b)%n+n)%n])%mod;
    cout<<f[n-1][(s%n+n)%n];
    return 0;
}
posted @ 2022-02-22 22:13  zyy2001  阅读(100)  评论(0编辑  收藏  举报