观察这个数列:
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加2或者减少3,且每一项都为整数。
栋栋对这种数列很好奇,他想知道长度为 nn 和为 ss 而且后一项总是比前一项增加 aa 或者减少 bb 的整数数列可能有多少种呢?
输入格式
共一行,包含四个整数 n,s,a,bn,s,a,b,含义如前面所述。
输出格式
共一行,包含一个整数,表示满足条件的方案数。
由于这个数很大,请输出方案数除以 100000007100000007 的余数。
数据范围
1≤n≤10001≤n≤1000,
−109≤s≤109−109≤s≤109,
1≤a,b≤1061≤a,b≤106
输入样例:
4 10 2 3
输出样例:
2
样例解释
两个满足条件的数列分别是2 4 1 3和7 4 1 -2。
题解:
发现数列直接写出来是这样:
拆开括号:
转化:
转化:
发现只有当s/n的余数和后半的余数相同时,x才能是整数。
于是DP[i][j]就出来了,代表当有i个a的时候(剩下n-1-i为b)余数为j的个数。
状态转移方程为:
其中x是 (i*a) % n。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
typedef long long int ll;
long long int MOD=1e8+7;
int n,s,a,b;
int dp[1001][1001]={{0}};
int col(int a){
while(a<0){
a+=n;
}
return a;
}
main(){
cin >> n >> s >> a >> b;
b*=(-1);
int t1=a%n,t2=b%n;
if(a%n<0){
t1=col(a%n);
}
if(b%n<0){
t2=col(b%n);
}
//cout << t1 << " " << t2 << "\n";
dp[t1][1]++;dp[t2][1]++;
for(int i=2;i<n;i++){
int x=(i*a)%n;int y=(i*b)%n;
//cout << x << " " << y << "\n";
if(x<0){
x=col(x);
}
if(y<0){
y=col(y);
}
//cout << x << " " << y << "\n";
for(int j=0;j<n;j++){
//cout << "j: " << (j+x)%n << " i: " << (j+y)%n << "\n";
if(dp[j][i-1]>0){
dp[(j+x)%n][i]=(dp[(j+x)%n][i]+(dp[j][i-1]))%MOD;
dp[(j+y)%n][i]=(dp[(j+y)%n][i]+(dp[j][i-1]))%MOD;
}
}
}
/*
for(int i=0;i<n;i++){
for(int j=0;j<=n;j++){
cout << dp[i][j] << ' ';
}
cout << "\n";
}
*/
int tt=s%n;
tt=col(tt);
dp[tt][n-1]%=MOD;
cout << dp[tt][n-1];
}