问题描述
观察这个数列:
1 3 0 2 -1 1 -2 ...
这个数列中后一项总是比前一项增加2或者减少3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?
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。
对于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。
当n等于1的时候,很明显方案数为1
当n>1时,
假设波动序列为 x,x+d1,x+d1+d2, ... , x+d1+d2+...+dn-1
构造差值序列: {d}={d1,d2,d3,...,dn-1}
把{d}序列数列翻一下,得到f序列: {f}={dn-1,...,d3,d2,d1}
则 s =x+(x+d1)+(x+d1+d2)+...+(x+d1+d2+...+dn-1)
=nx+(n-1)d1+(n-2)d2+...+dn-1
=nx+dn-1+2dn-2+....+(n-1)d1
=nx+f1+2f2+...+(n-1)fn
由于第一个数x是整数,所以原问题等价于求
满足式子 s=f1+2f2+...+(n-1)fn-1 (mod n)
的{f}序列的方案数,其中{f}序列的元素只能是a或者-b
从上面红色的式子,我们可以看出,当s增加n的整数倍时
满足 s+tn=f1+2f2+...+(n-1)fn-1 (mod n)
就等同于满足 s=f1+2f2+...+(n-1)fn-1 (mod n)
所以当s增加n的整数倍的时候,方案数是不会变的
比如在n=4时, s=7和s=3求解出来的方案数是一样的
所以我们没必要对于每个s都求解出结果,只需要求解出 s=0 s=1 s=2 s=3 就可以
s=7的解就同于s=3的解 g(7)=3
s=8的解等同于s=0的解 g(8)=0
。。。
规定g函数为: 整数->{0,1,2,...,n-1}的映射
假设 f[g(s),n-1]为满足式子
s=f1+2f2+...+(n-1)fn-1 (mod n)
的方案数
那么有递推公式: sa=s-(n-1)*a;
sb=s+(n-1)*b
f[g(s),n-1]=f[g(sa
),n-2]+f[g(sb)
,n-2]
当fn-1取a时, sa=s-(n-1)*a
当fn-1取-b时,sb=s+(n-1)*b
再把sa,sb代入 f[g(s),(n-1)-1]就可以得到上面的递推关系式
现在,我们来手算题目给的例子 4 10 2 3(n,s,a,b)
一开始初始化第一列为1,0,0,0
接着一列一列开始填数( f[i,j]=f[g(i-j*a),i-1]+f[g(i+j*b),i-1])
f[0,1]=f[g(-2),0]+f[g(3),0]
=f[2,0]+f[3,0]
=0+0
=0
把一列填完,接着填第二列
f[0,2]=f[g(-4),1]+f[g(6),1]
=f[0,1]+f[2,1]
=0+1
=1
这样一列列填完。。。
填完这个f[n][n]的数组之后
要求 s=10,n=4的方案数 即是 f[g(10)][3]
返回f[0][3]的值就是答案2
接下来只需要把手算的过程用机器算就行
对于输入的n
如果n=1,返回1
如果n>1,机器模拟填数过程,返回f[g(s)][n-1]
代码如下:
import java.util.Scanner;
public class Main {
static int n, s, a, b;
static int f[][];
static int modnum = 100000007;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
s=sc.nextInt();
a=sc.nextInt();
b=sc.nextInt();
f=new int[n][n];
f[0][0]=1;
System.out.println(c());
}
private static int c()
{
if(n==1)
return 1;
for(int j=1;j<n;j++)
for(int i=0;i<n;i++)
f[i][j]=(f[g(i-j*a)][j-1]+f[g(i+j*b)][j-1])% modnum;
return f[g(s)][n-1];
}
private static int g(int v)
{
return ((v%n)+n)%n;
}
}
这道题比较难理解,本人讲解水平有限,看不懂的直接看代码把