*波动数列c++

题目

输入样例:

4 10 2 3

输出样例:

2

样例解释

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

思路

上来先理解题意,本题求的是“长度为n  总和为s的……数列的数目”。

假设第一项为x,增加 a 或者减少 b用di表示,那么满足题目要求(后一项总是比前一项增加 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}          (1)

数列前n项的和 s可以表示为:

s = nx + (n - 1)d_{1} + (n - 2)d_{2}, (n - 3)d_{3} ...+ (n - i)d_{i} + ... + d_{n}

那么:

x =\frac{​{s - \left [(n - 1)d_{1} + (n - 2)d_{2} + (n - 3)d_{3} ...+ (n - i)d_{i} + ... + d_{n}\right ]}}{n}                 (2)

        

        从上面(2)式可以看出,对于确定的s,n,每个x都由一组(d1, d2, ..., dn)唯一确定,同时,如果确定了一个x,那么一组(d1, d2, ..., dn)也会唯一确定,即一个数列就确定了,因此(d1, d2, ..., dn)的合法组数等于满足题目要求的数列总数。

        那什么样的一组(d1, d2, ..., dn)是合法解?由于x是整数,因此(2)式中的分子必须是n的倍数,即s和(n - 1)d_{1} + (n - 2)d_{2}, ... + d_{n}模n要同余。

状态表示

由上分析得知本题涉及到的变量为(d1, d2, ..., dn),以及(n - 1)d_{1} + (n - 2)d_{2}, ... + d_{n} mod n的同余数j。那么只要算出所有(n - 1)d_{1} + (n - 2)d_{2}, ... + d_{n}的组合模n的余数,将不同余数用一个数组f统计起来,比如余数为1的组合有多少种。那么最后输出f[s%n]即可。

  • 集合定义f[i, j]:对于(d1,d2,…di,...dn),只考虑前i项,当前的总和(注意是(n - 1)d_{1} + (n - 2)d_{2}, ... + d_{i}的总和)除以n的余数为j的组合 的集合(数目)。
  • 属性:前i项,当前总和除以n的余数为j的组合 的集合(数目)。

状态计算

状态计算一般就是抓住最后一步的不同来划分集合。本题最后一步的di可能为 加a 或者 减b

(1≤a,b≤10^6),划分的集合可看下图。

        假设组合(d1,d2,…di)的第i项di为a,((n - 1)d_{1} + (n - 2)d_{2}, ... + (n - i)a) mod n \equiv j

        那怎么由前面的状态推出f[i, j]呢?我们知道不管前i - 1项中的d是怎么变化的,只要是第i项di为a,并且((n - 1)d_{1} + (n - 2)d_{2}, ... + (n - i)a) mod n \equiv j 的(d1,d2,…di-1)组合都是合法的。那么这些(d1,d2,…di-1)组合的个数又怎么求呢??

我们两边都减去(n - i)a,得:

((n - 1)d_{1} + (n - 2)d_{2}, ... (n - i + 1)d_{i - 1}) mod n \equiv (j - (n - i)a)mod n

发现左式的余数和 j - (n - i)a mod n的余数相同,根据集合定义,f[i - 1][([ j - (n - i)*a) mod n] 就是这些(d1,d2,…di-1)组合的个数。

        而对于第i项di为-b,同理可得f[i - 1][([ j + (n - i)*a) mod n] 就是这些(d1,d2,…di-1)组合的个数。

细节

  • 下标不能为负,j - (n - i)*a 可能为负数,而c++中对一个负数取模,相当于先用负数的绝对值取模,然后再加负号。 
  • 长度n = 1时,根据(2)式,x只能是0。那么f[0][0] = 1(别忘了集合定义!!

代码
/*一道题,一包烟,一坐就是一整天*/
#include<bits/stdc++.h>
using namespace std;
const int MOD = 100000007, N = 1010;
int f[N][N];
int n, s, a, b;

//求x mod n的正余数
int get_mod(int x)
{
  return (x % n + n) % n;
}

int main()
{
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  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][j] + f[i - 1][get_mod(j - (n - i)*a)]) % MOD;
      f[i][j] = (f[i][j] + f[i - 1][get_mod(j + (n - i)*b)])  % MOD;
    }
  }
  //s可能为负数!!
  cout << f[n - 1][get_mod(s)];
  
}

资料

模运算定理

相关推荐

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

    2024-03-16 05:52:02       67 阅读
  2. 每日算法打卡:波动数列 day 16

    2024-03-16 05:52:02       55 阅读
  3. [蓝桥杯 2014 省 A] 波动数列

    2024-03-16 05:52:02       46 阅读
  4. Python实战:分析产品价格波动数据探索

    2024-03-16 05:52:02       36 阅读
  5. 矩阵力学和波动力学

    2024-03-16 05:52:02       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-16 05:52:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-16 05:52:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-16 05:52:02       87 阅读
  4. Python语言-面向对象

    2024-03-16 05:52:02       96 阅读

热门阅读

  1. 基于 ARM 的 Linux 上的 PX4 开发环境设置错误

    2024-03-16 05:52:02       32 阅读
  2. Flink异步io关联Hbase

    2024-03-16 05:52:02       43 阅读
  3. 【WEEK3】学习目标及总结【SpringMVC】【中文版】

    2024-03-16 05:52:02       51 阅读
  4. python文件的打开及open方法

    2024-03-16 05:52:02       43 阅读
  5. 云计算与低代码:重塑软件开发的新范式

    2024-03-16 05:52:02       44 阅读
  6. 三、贪心算法

    2024-03-16 05:52:02       44 阅读
  7. 13 list的实现

    2024-03-16 05:52:02       44 阅读
  8. 海外十大海外视频媒体推广网站-大舍传媒

    2024-03-16 05:52:02       38 阅读
  9. 如何高效使用ChatGPT技巧

    2024-03-16 05:52:02       38 阅读
  10. 视频和图像编码标准或格式的发展关系

    2024-03-16 05:52:02       37 阅读
  11. SpringMVC基础之简单程序应用

    2024-03-16 05:52:02       41 阅读