• 波动数列


    问题描述
      观察这个数列:
      1 3 0 2 -1 1 -2 ...

      这个数列中后一项总是比前一项增加2或者减少3。

      栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?
    输入格式
      输入的第一行包含四个整数 n s a b,含义如前面说述。
    输出格式
      输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。
    样例输入
    4 10 2 3
    样例输出
    2
    样例说明
      这两个数列分别是2 4 1 3和7 4 1 -2。
    数据规模和约定
      对于10%的数据,1<=n<=5,0<=s<=5,1<=a,b<=5;
      对于30%的数据,1<=n<=30,0<=s<=30,1<=a,b<=30;
      对于50%的数据,1<=n<=50,0<=s<=50,1<=a,b<=50;
      对于70%的数据,1<=n<=100,0<=s<=500,1<=a, b<=50;
      对于100%的数据,1<=n<=1000,-1,000,000,000<=s<=1,000,000,000,1<=a, b<=1,000,000。
     
      思路:数论+DP.       总和s如此巨大,不能开个如此大的DP数组。设N个数的和为sum,  如果sum%n==s%n==r,   那么sum=k*n+r.  也就是对n个数每个数+k1,  sum+k1*n=s;         问题转换为和的余数为r=s%n的组合有多少个。   那么数组就可以开得下了。
     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<algorithm>
     7 using namespace std;
     8 const int Mod=100000007;
     9 int dp[1005][1005];
    10 int main()
    11 {
    12     int n,s,a,b;
    13     scanf("%d%d%d%d",&n,&s,&a,&b);
    14     dp[1][0]=1;//不妨设首项为0
    15     for(int i=1;i<n;i++)
    16     {
    17         for(int j=0;j<n;j++)
    18         {
    19             //计算每一次+a或者-b对数列之和sum的贡献
    20             dp[i+1][(j+(n-i)*a)%n]=(dp[i+1][(j+(n-i)*a)%n]+dp[i][j])%Mod;
    21             dp[i+1][(j+i*b)%n]=(dp[i+1][(j+i*b)%n]+dp[i][j])%Mod;
    22             //等价于dp[i+1][(j-(n-i)*b)%n]+=dp[i][j];
    23         }
    24     }
    25     s=(s+1000000000LL*n)%n;//保证s非负且不改变s mod n的值
    26     printf("%d
    ",dp[n][s%n]);
    27     //若sum=s(mod n)则可以改变首项使得数列满足条件
    28     return 0;
    29 }
     
  • 相关阅读:
    框架
    css样式表。作用是美化HTML网页.
    表单的制作
    表格的制作
    常用标签的制作
    标签的制作
    poj2104(K-th Number)
    Codeforces Round #359 (Div. 2) D. Kay and Snowflake
    Codeforces Round #359 (Div. 2) C. Robbers' watch
    HDU3308(LCIS) 线段树好题
  • 原文地址:https://www.cnblogs.com/767355675hutaishi/p/4320348.html
Copyright © 2020-2023  润新知