波动数列

波动数列
 

Description

 

观察这个数列:

1 3 0 2 -1 1 -2 ...

这个数列中后一项总是比前一项增加2或者减少3。

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

 

Input

 

输入的第一行包含四个整数 n s a b,含义如前面说述。

 

Output

 

输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。

 粘一下大佬的代码!滚动数组实在看不懂,但是这个非常可以!

https://blog.csdn.net/SunMoonVocano/article/details/79464889?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

/*
思路:设第一个元素为a0:若想让最后和为s
则要满足 sum = a[0]+a[1]+...+a[n-1] = s
由于a[k] 是由 a[k-1] 通过+a或者-b得到的
所以任何 i < k 若a[i]都会对他产生影响
例如:若每次都是加a操作则a[]的值如下 
a0  a0
a1  a0 + a
a2  a0 + a + a
a3  a0 + a + a + a
..... 
也就是说第一次加a 那么 sum 就会加上n-1个a
然后依次递减一个,减b相似
但是不管加a或者减b,总的操作的次数为max = (n-1)*n/2次;
其中+a的次数可能为 0到max任何值。一旦+a的次数确定了不妨设为numa,
 -b的次数随之确定,又因为 s = N*a0 + numa*a - (max-numa)*b;
 若枚举+a的次数,其中只有a0未知,如果a0有整数解,则满足,就加上
 该种情况下的方案数。
 
 最后就是计算方案数,一旦numa给定,总的可能的方案有多少呢?
 其实问题一转化,就变成了求从 1,2... n-1 任意取数,能够组成numa的
 方案数,设该问题为dp[n-1][numa]; 对于一般的dp[i][j] 表示从1-i中选出
 任意个数,使得和为j对第i个数特殊考虑,就有第i个数存在于j内有dp[i-1][j-i]种
 方案。若不在则有dp[i-1][j]种方案。 
 所以 : dp[i][j] = dp[i-1][j] + dp[i-1][j-i];
 若用滚动数组,就可省去一维。 
 
*/ 
#include <iostream>
using namespace std;
typedef long long ll;
 
const ll mod = 100000007;
ll dp[10000006];
 
int main()
{
    ll n,s,a,b;
    cin>>n>>s>>a>>b;
    ll ans = 0;
    
    dp[0] = 1;
    for(ll i = 1; i < n; i++)
        for(ll j = i*(i+1)/2; j >= i; j--)
            dp[j] = (dp[j-i] + dp[j])%mod;
        
    for(ll i = 0; i <= (n-1)*n/2; i++)
    {
        ll tmp = s + i*a - ((n-1)*n/2 - i) * b;
        if(tmp % n == 0) ans = (ans+dp[i])%mod;  
    } 
    cout << ans <<endl;
    return 0;
}

 

posted on 2020-10-07 20:29  Taurus20000519  阅读(165)  评论(0)    收藏  举报