問題描述:
觀察如下數列:
1 3 0 2 -1 1 -2 …
這個數列中后一項總是比前一項增加 2 或者減少 3。
棟棟對這種數列很好奇,他想知道長度為 n nn 和為 s ss 而且后一項總是比前一項增加 a aa 或者減少 b bb 的整數數列可能有多少種呢?
輸入格式
輸入的第一行包含四個整數 n ? s ? a ? b n\ s\ a\ bn s a b,含義如前面說述。
輸出格式
輸出一行,包含一個整數,表示滿足條件的方案數。由于這個數很大,請輸出方案數除以 100000007 的余數。
樣例輸入
4 10 2 3
樣例輸出
2
樣例說明
這兩個數列分別是 {2 4 1 3} 和 {7 4 1 -2}。
暴力解法(超時):
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
#define base 100000007
int n,s,a,b;
long long sum=0;
void check(int k)
{double change=s-k;double first=change/n;if(fmod(first,1)==0){//計算出的第一個數為整數sum++;sum%=base;}
}
void calculate(int,int);int main()
{cin>>n>>s>>a>>b;calculate(n-1,0);cout<<sum;return 0;
}
void calculate(int layer,int u)
{//遞歸出口if(layer==0){check(u);return;}int addition=layer*a;calculate(layer-1,u+addition);addition=(-b)*layer;calculate(layer-1,u+addition);
}
動態規劃:
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
#define base 100000007
long long a,b,n,s;
const int N=1000010;
int f[N]={0};
//f[i][j]表示從(1~n-1)中前i個數中選擇使得和為j的種類數
//f[i][j]=f[i-1][j]+f[i-1][j-i]; f[i][0]=1;
void create()
{//參考01背包問題f[0]=1;for(int i=1;i<=n-1;i++){int num=i*(i+1)/2;for(int j=num;j>=i;j--){//需要倒序使得f[j-1]為f[i-1][j-1];f[j]=(f[j]+f[j-i])%base;}}
}void calculate();int main()
{cin>>n>>s>>a>>b;create();calculate();return 0;
}
void calculate()
{int num=n*(n-1)/2;long long sum=0;for(int i=0;i<=num;i++){long long u=i*a-(num-i)*b;long long temp=s-u;if(temp%n==0){//n-1個位置取i個位置sum=(sum+f[i])%base;}}cout<<sum;
}