[蓝桥杯 2014 省 A] 波动数列

题目链接

蓝桥杯 2014 省 A 波动数列

题目描述

观察这个数列:

1 3 0 2 − 1 1 − 2 ... 1\ 3\ 0\ 2\ -1\ 1\ -2\ ... 1 3 0 2 −1 1 −2 ...

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

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

输入格式

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

输出格式

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

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

数据范围
  • 1 ≤ n ≤ 1000 1≤n≤1000 1≤n≤1000

  • − 1 0 9 ≤ s ≤ 1 0 9 −10^9≤s≤10^9 −109≤s≤109

  • 1 ≤ a , b ≤ 1 0 6 1≤a,b≤10^6 1≤a,b≤106

输入样例:

4 10 2 3

输出样例:

2

样例解释

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

解法:同余 + dp

我们可以列出数列的 n n n 项,这里假设 x x x 是第一项, d 1 , d 2 , . . . , d n − 1 d_1,d_2,...,d_{n-1} d1,d2,...,dn−1的值为 a a a 或者 b b b :

s = ( x ) + ( x + d 1 ) + ( x + d 1 + d 2 ) + . . . + ( x + d 1 + d 2 + . . . + d n − 1 ) s = (x) + (x + d_1) + (x + d_1 + d_2) + ... + (x + d_1 + d_2 + ... + d_{n - 1}) s=(x)+(x+d1)+(x+d1+d2)+...+(x+d1+d2+...+dn−1)

将其整理一下可以得到 :
s = n × x + ( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( d n − 1 ) s = n \times x + (n - 1)d_1 + (n - 2)d_2 + ... + (d_{n - 1}) s=n×x+(n−1)d1+(n−2)d2+...+(dn−1)

由于 x x x 可以是任意的整数,而 s s s 是给定的,也就是确定的,于是我们可以通过 s s 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−(n−1)d1+(n−2)d2+...+(dn−1)

由于 x x x ,也就是数列的第一项,必须是整数。

所以, n n n 必须能够整除 s − ( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( d n − 1 ) s - (n - 1)d_1 + (n - 2)d_2 + ... + (d_{n - 1}) s−(n−1)d1+(n−2)d2+...+(dn−1),也就是 s − ( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( d n − 1 ) s - (n - 1)d_1 + (n - 2)d_2 + ... + (d_{n - 1}) s−(n−1)d1+(n−2)d2+...+(dn−1) 除以 n n n 的余数为 0 0 0。

我们能够进一步推导出 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}) (n−1)d1+(n−2)d2+...+(dn−1) 除以 n n n 的余数相等,也就是 s m o d n ≡ ( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( d n − 1 ) m o d    n s\ mod\ n \equiv (n - 1)d_1 + (n - 2)d_2 + ... + (d_{n - 1}) \mod n s mod n≡(n−1)d1+(n−2)d2+...+(dn−1)modn,即 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}) (n−1)d1+(n−2)d2+...+(dn−1) 同余 n n n。

所以我们将原问题转换为:求使得 ( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( d n − 1 ) (n - 1)d_1 + (n - 2)d_2 + ... + (d_{n - 1}) (n−1)d1+(n−2)d2+...+(dn−1) 和 s s s 同余 n n n 的方案数有多少种。

我们定义 f i j fij fij 为从前 i i i 项中选,第 i i i 项元素比前一个 增加 a a a 或者 减少 b b b ,且模 n n n 余数是 j j j 的方案数。

如果第 i i i 项元素选的是 + a +a +a:

( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( n − ( i − 1 ) ) d i − 1 + ( n − 1 ) a m o d n ≡ j (n - 1)d_1 + (n - 2)d_2 + ... + (n - (i - 1))d_{i - 1} + (n - 1)a \ mod\ n \equiv j (n−1)d1+(n−2)d2+...+(n−(i−1))di−1+(n−1)a mod n≡j

将其转换一下:

( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( n − ( i − 1 ) ) d i − 1 m o d n ≡ j − ( n − 1 ) a m o d n (n - 1)d_1 + (n - 2)d_2 + ... + (n - (i - 1))d_{i - 1} \ mod\ n \equiv j - (n - 1)a \ mod\ n (n−1)d1+(n−2)d2+...+(n−(i−1))di−1 mod n≡j−(n−1)a mod n

所以我们可以得到 f i j = f i − 1 j − ( n − 1 ) a fij = fi - 1j - (n - 1)a fij=fi−1j−(n−1)a

如果第 i i i 项元素选的是 − b -b −b:

( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( n − ( i − 1 ) ) d i − 1 − ( n − 1 ) b m o d n ≡ j (n - 1)d_1 + (n - 2)d_2 + ... + (n - (i - 1))d_{i - 1} - (n - 1)b \ mod\ n \equiv j (n−1)d1+(n−2)d2+...+(n−(i−1))di−1−(n−1)b mod n≡j

将其转换一下:

( n − 1 ) d 1 + ( n − 2 ) d 2 + . . . + ( n − ( i − 1 ) ) d i − 1 m o d n ≡ j + ( n − 1 ) b m o d n (n - 1)d_1 + (n - 2)d_2 + ... + (n - (i - 1))d_{i - 1} \ mod\ n \equiv j + (n - 1)b \ mod\ n (n−1)d1+(n−2)d2+...+(n−(i−1))di−1 mod n≡j+(n−1)b mod n

所以我们可以得到 f i j = f i − 1 j + ( n − 1 ) b fij = fi - 1j + (n - 1)b fij=fi−1j+(n−1)b

综上,我们可以得出:

f i j = f i − 1 j + ( n − 1 ) b + f i − 1 j − ( n − 1 ) a fij = fi - 1j + (n - 1)b + fi - 1j - (n - 1)a fij=fi−1j+(n−1)b+fi−1j−(n−1)a

注意:

  • 由于 j − ( n − 1 ) a j - (n - 1)a j−(n−1)a 可能小于 0 0 0,我们必须保证它模 n n n 为正数。令 t = j − ( n − 1 ) a t = j - (n - 1)a t=j−(n−1)a,那么我们最终得到的余数应该是 ( t m o d n + n ) m o d n (t\ mod\ n + n)\ mod\ n (t mod n+n) mod n,这样就保证了最终的余数是正数。
  • f 0 0 f00 f00 应该初始化为 1 1 1,因为他表示什么也不选也是一种方案,什么也不选那么就只有第一项 x x x。
  • 我们最终返回的答案就是 f n − 1 ( s m o d n + n ) m o d n fn - 1(s\\ mod\\ n + n)\\ mod\\ n fn−1(s mod n+n) mod n,因为 s s s 有可能是负数,所以我们也需要保证它模 n n n 是一个正数。

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

C++代码:

cpp 复制代码
#include <iostream>

using namespace std;

const int N = 1010 , MOD = 100000007;
int f[N][N];

int get_mod(int a , int b){
    return (a % b + b) % b;
}

int main(){
    int n , s, a, b;
    cin>>n>>s>>a>>b;
    
    f[0][0] = 1;
    for(int i = 1;i < n;i++){
        for(int j = 0;j < n;j++){
            int &val = f[i][j];
            val = (val + f[i - 1][get_mod(j - (n - i) * a , n)]) % MOD;
            val = (val + f[i - 1][get_mod(j + (n - i) * b , n)]) % MOD;
        }
    }
    
    cout<<f[n - 1][get_mod(s , n)]<<'\n';
}

Java代码:

java 复制代码
import java.io.*;
import java.util.*;

public class Main{
    static final int N = 1010 , MOD = 100000007;
    static long[][] f = new long[N][N];
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    
    public static int get_mod(int a , int b){
        return (a % b + b) % b;
    }
    
    public static void main(String[] args) throws Exception{
        String[] s1 = in.readLine().split(" ");
        int n = Integer.parseInt(s1[0]);
        int s = Integer.parseInt(s1[1]);
        int a = Integer.parseInt(s1[2]);
        int b = Integer.parseInt(s1[3]);
        
        f[0][0] = 1;
        for(int i = 1;i < n;i++){
            for(int j = 0;j < n;j++){
                f[i][j] = (f[i][j] + f[i - 1][get_mod(j - (n - i) * a , n)]) % MOD;
                f[i][j] = (f[i][j] + f[i - 1][get_mod(j + (n - i) * b , n)]) % MOD;
            }
        }
        
        System.out.println(f[n - 1][get_mod(s,n)]);
    }
}
相关推荐
汉克老师1 天前
GESP6级C++考试语法知识(五十五、动态规划----背包问题(八、混合背包)
c++·动态规划·dp·背包问题·gesp六级·混合背包问题
2601_961194023 天前
教资科三美术考什么|初中高中美术题型考点和模板资料
leetcode·elasticsearch·职场和发展·蓝桥杯·pat考试·lucene
h_a_o777oah3 天前
2026 蓝桥杯软件 C++B组 国赛比赛经历及备赛建议
c++·经验分享·算法·蓝桥杯
迈巴赫车主4 天前
蓝桥杯21241灯塔java
java·开发语言·数据结构·算法·职场和发展·蓝桥杯·动态规划
大学竞赛君4 天前
第十六届蓝桥杯大赛软件赛决赛 Python 大学 A 组
python·职场和发展·蓝桥杯
此生决int5 天前
算法从入门到精通——字符串
数据结构·c++·算法·蓝桥杯
飞天狗1116 天前
2024第十五届蓝桥杯c/c++B组国赛题解
c语言·数据结构·c++·算法·蓝桥杯
casual~7 天前
十六届蓝桥杯国赛个人题解
经验分享·学习·算法·蓝桥杯
wanderist.7 天前
14决赛蓝桥杯
职场和发展·蓝桥杯
江屿风8 天前
C++OJ题经验总结(竞赛)4
开发语言·c++·笔记·算法·dp·双指针