小言_互联网的博客

1214. 波动数列(推公式 + DP)

354人阅读  评论(0)

题目如下:

思路 or 题解:

我们可以设: 第一个数为 x x x
d = {a, -b}
那后续的数为: x + d 1 x + d_1 x+d1 , x + d 1 + d ) 2 x + d_1 + d_)2 x+d1+d)2 … … x + d 1 + d 2 + . . . . . . + d n − 1 x + d_1 + d_2 + ... ... + d_{n - 1} x+d1+d2+......+dn1
根据题意和上面的式子
我们合并一下同类项:
n ∗ x + ( n − 1 ) ∗ d 1 + ( n − 2 ) ∗ d 2 + . . . . . . + d n − 1 = s n * x + (n - 1) * d_1 + (n - 2) * d_2 + ... ... + d_{n-1} = s nx+(n1)d1+(n2)d2+......+dn1=s
我们可以解出 x x x
x = s − [ ( n − 1 ) ∗ d 1 + ( n − 2 ) ∗ d 2 + . . . . . . + d n − 1 ) ] n x = \frac{s- [(n - 1) * d_1 + (n - 2) * d_2 + ... ... + d_{n-1})]}{n} x=ns[(n1)d1+(n2)d2+......+dn1)]
又因为 x x x 是任意整数,我们可以得出来:
s s s ( n − 1 ) ∗ d 1 + ( n − 2 ) ∗ d 2 + . . . . . . + d n − 1 ) (n - 1) * d_1 + (n - 2) * d_2 + ... ... + d_{n-1}) (n1)d1+(n2)d2+......+dn1) 同余 n n n
这就将题转变成组合问题了,可以用背包的思想去解决!

状态表示:
f [ i ] [ j ] f[i][j] f[i][j] 选了 i i i d d d, 余数为 j j j 的方案数。
状态计算:

  • 选 a: f [ i ] [ j ] = f [ i − 1 ] [ j − a ∗ i ] f[i][j] = f[i-1][j - a * i] f[i][j]=f[i1][jai]
  • 选 -b: d [ i ] [ j ] = f [ i − 1 ] [ j + b ∗ i ] d[i][j] = f[i - 1][j + b*i] d[i][j]=f[i1][j+bi]
    特别注意: C++数组下标不能取负数,所以我们需要写一个函数,来确保计算出来的数为非负数。
auto getmod = [&](int x)
    {
   
        return (x % n + n) % n;
    };

时间复杂度: 0 ( n 2 ) 0(n^2) 0(n2)

AC 代码:

const int mod = 100000007;
const int inf = 2147483647;
const int N = 100009;
int n, s, a, b;
int f[1009][1009];
void solve()
{
   
    cin >> n >> s >> a >> b;
    f[0][0] = 1;
    auto getmod = [&](int x)
    {
   
        return (x % n + n) % n;
    };
    for (int i = 1; i < n; i++)
        for (int j = 0; j < n; j++)
            f[i][j] = (f[i - 1][getmod(j - a * i)] + f[i - 1][getmod(j + b * i)]) % mod;
    
    cout << f[n - 1][getmod(s)] << '\n';
}
int main()
{
   
    buff;
    solve();
}

 

转载:https://blog.csdn.net/m0_60593173/article/details/128515833
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场