(排列,选择类dp)(数论同余定理,同余运算)(以背包为母题)1214. 波动数列

简介: (排列,选择类dp)(数论同余定理,同余运算)(以背包为母题)1214. 波动数列

1214. 波动数列 - AcWing题库


// 卡壳,漏了题目关键流程要取模,由于是例题就没有按流程debug导致

// 错误:i的范围应该是1到n-1,因为数组的第一项是任意的,且已经分离出去了,这里只有第二项开始往后的数

// 卡壳,j的范围没有确定好,模n余数应该是0到n-1

// 错误取模的数错误,这里数组保存的是题目结果,应该模 100000007,n是对于下标才要模的数

dp分析时,在分析状态表示时,要分析每一维的取值范围

最后检查范围时,不仅要检查数据范围,还要检查取模情况

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
// // c++中的负数取模会得到负数,但数学中的负数取模是应该得到正数的,要写上一个取模函数把负数取模补正
int get_mod(int a,int b){
    return (a % b + b) % b;
}
// 卡壳,漏了题目关键流程要取模,由于是例题就没有按流程debug导致
const int N = 1e3 + 10,MOD =  100000007;
int f[N][N];
int main(){
    int n,s,a,b;
    cin >> n >> s >> a >> b;
    f[0][0] = 1;
    for(int i = 1;i <= n;i++){
        // 错误:i的范围应该是1到n-1,因为数组的第一项是任意的,且已经分离出去了,这里只有第二项开始往后的数
        for(int j = 0;j <= n;j++){ 
            // 卡壳,j的范围没有确定好,模n余数应该是0到n-1
            f[i][j] = (f[i-1][get_mod(j-(n-i)*a,n)] + f[i-1][get_mod(j + (n-i)*b,n)]) % MOD; 
            // 错误取模的数错误,这里数组保存的是题目结果,应该模 100000007,n是对于下标才要模的数
        }
    }
    cout << f[n-1][get_mod(s,n)];
    // 错误,同i范围没有确定的连带错误
    return 0;
}

思路

// 1≤n≤1000

// ,

// −109≤s≤109

// ,

// 1≤a,b≤106

// 范围在暗示用枚举类的方法,想dfs,dp

// 观察这个数列:


// 1 3 0 2 -1 1 -2 …


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


// 栋栋对这种数列很好奇,他想知道长度为 n

// 和为 s

// 而且后一项总是比前一项增加 a

// 或者减少 b

// 的整数数列可能有多少种呢?

// 表达式


// x + x + d1 + x + d1 + d2 + x + d1 + d2 + d3 + ... = s;

// s = n*x + (n-1)d1 + (n-2)d2 + (n-3)*d3 + ...;

// x无限制,用有限制的量来表示

// s - ((n-1)d1 + (n-2)d2 + (n-3)*d3 + ...) / n = x;

// 因为x是整数,所以

// s - ((n-1)d1 + (n-2)d2 + (n-3)*d3 + ...)一定是n的倍数

// 根据?同余定理,

// s 同余 ((n-1)d1 + (n-2)d2 + (n-3)*d3 + ...) (mod n)

// 看((n-1)d1 + (n-2)d2 + (n-3)*d3 + ...),要枚举每一个d选a还是b,可以开始dp分析,

// 两个选择的dp,排列问题dp,选择问题dp,(母题为背包问题)


// // 状态表示 f[i][j] 二维数组表示考虑前i项,j表示余数的情况数

// // 属性 :情况数

// 情况数属性要边界初始化

// // // 状态表示写的时候考虑好取值范围


// // i范围是1到n-2,因为这里通过变换把第一项给去掉了,所以少一项

// // j的范围,0到n

// // 状态计算 集合划分,最后一项不同的,f[i][j],第i项选a f[i-1][j-(n-1)*a]

// // 第i项选b f[i-1][j+(n-1)*b]

// // 第i项选a的话,余数加上(n-1)*a = j,所以i-1的余数是(j-(n-1)*a)%n

// // 第i项选b的话,余数减去(n-1)*b = j;所以i-1的余数是(j+(n-1)*b;)%n

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

// // 的余数。

// // f[i][j] = (f[i-1][(j-(n-1)*a)%n] + f[i-1][(j+(n-1)*b)%n])%mod;

// // c++中的负数取模会得到负数,但数学中的负数取模是应该得到正数的,要写上一个取模函数把负数取模补正


// 检查范围

// 1≤n≤1000

// ,

// −109≤s≤109

// ,

// 1≤a,b≤106

// 取模是1e8的,没有*10操作,不可能爆int


目录
相关文章
|
2天前
|
算法 测试技术 C++
【动态规划 区间dp 位运算】3117. 划分数组得到最小的值之和
【动态规划 区间dp 位运算】3117. 划分数组得到最小的值之和
【动态规划 区间dp 位运算】3117. 划分数组得到最小的值之和
|
2天前
|
算法 测试技术 C#
【数位dp】【数论】【动态规划】2999. 统计强大整数的数目
【数位dp】【数论】【动态规划】2999. 统计强大整数的数目
|
2天前
|
人工智能 算法
前缀和算法题(区间次方和、小蓝平衡和、大石头的搬运工、最大数组和)
前缀和算法题(区间次方和、小蓝平衡和、大石头的搬运工、最大数组和)
|
2天前
|
算法 测试技术 C++
【组合数学】【动态规划】【前缀和】1735生成乘积数组的方案数
【组合数学】【动态规划】【前缀和】1735生成乘积数组的方案数
|
2天前
|
机器学习/深度学习 存储 算法
数据结构与算法面试题:给定非负整数 m 和 n,计算不大于 m 的数字中,素数的个数。(提示:算法原理为埃氏筛、线性筛)
数据结构与算法面试题:给定非负整数 m 和 n,计算不大于 m 的数字中,素数的个数。(提示:算法原理为埃氏筛、线性筛)
38 0
|
9月前
|
人工智能 算法 决策智能
动态规划之背包问题(01背包问题、完全背包问题、方案数填满型背包问题)
动态规划之背包问题(01背包问题、完全背包问题、方案数填满型背包问题)
143 1
|
9月前
|
人工智能 算法 BI
【贪心策略】区间问题、背包问题、贪心策略注意事项
【贪心策略】区间问题、背包问题、贪心策略注意事项
83 0
|
人工智能
(数论)(枚举)(前缀和)1230. K倍区间
(数论)(枚举)(前缀和)1230. K倍区间
62 0
|
人工智能
(闫氏dp分析法)(线性dp)(区间类dp)AcWing 895. 最长上升子序列
(闫氏dp分析法)(线性dp)(区间类dp)AcWing 895. 最长上升子序列
68 0
牛客IOI周赛23-普及组 D.小L的数列 (dp状态+枚举因子)
牛客IOI周赛23-普及组 D.小L的数列 (dp状态+枚举因子)
84 0