波动数列(组合问题求方案数)

波动数列

1214. 波动数列

在这里插入图片描述
思路O(n^2)

设第一个数为x,则第二个数为\(x+d1\),第三个数为\(x+d1+d2 …\)。这里的d1,d2表示a或者−b,所以这个数列为:
\(x,x + d_{1}, x + d_{1} + d_{2}, x + d_{1} + d_{2} + d_{3},... ...,x + d_{1} + d_{2} + ... + d_{n - 1}\)
和为s转换为:
\(n * x + (n - 1) * d_{1} + (n - 2) * d_{2} + ... ... + d_{n - 1} = s\)
转换为:
\(\frac{s - [(n - 1) * d_{1} + (n - 2) * d_{2} + ... + d_{n - 1}\ ]}{n} = x\)
\(s\)\((n - 1) * d_{1} + (n - 2) * d_{}2 + ... + d_{n - 1}\)模n的余数相同转换成组合问题

状态表示:f[i, j]表示要选i个a或者-b且余数为j的所有集合的方案数.
第 i 选a :\(f[i, j] = f[i - 1, j - (n - i) * a]\)
第 i 选b:\(f[i, j] = f[i - 1, j + (n - i) * b]\)

样例输入:

4 10 2 3

样例输出:

2

代码:

#include<iostream>
using namespace std;

const int N = 1010, mod = 100000007;

int n, s, a, b;
int f[N][N];  //选前i个数中 余数为j的方案数

int get_mod(int a, int b)   // 求a除以b的正余数    -->   core
{
    return (a % b + b) % b;
}

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][get_mod(j - (n - i) * a, n)] + f[i - 1][get_mod(j + (n  - i) * b, n)]) % mod;
        }
    }
    
    cout << f[n - 1][get_mod(s, n)] << endl;     
    
    return 0;
}



 

posted @ 2022-03-24 08:39  panse·  阅读(158)  评论(0)    收藏  举报