AcWing 1214. 波动数列
观察这个数列:
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加2或者减少3,且每一项都为整数。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 b 的整数数列可能有多少种呢?
输入格式
共一行,包含四个整数 n,s,a,b,含义如前面所述。
输出格式
共一行,包含一个整数,表示满足条件的方案数。
由于这个数很大,请输出方案数除以 100000007 的余数。
数据范围
1≤n≤1000,
−109≤s≤109,
1≤a,b≤106
输入样例:
4 10 2 3
输出样例:
2
样例解释
两个满足条件的数列分别是2 4 1 3和7 4 1 -2。
题意:求长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 b 的整数数列有多少种组合
实属带抽象题,嗯编是没思路,首先需要化简一下式子
参考https://www.acwing.com/solution/content/9223/
最后一句可以化简成s mod n与d1+2*d2+…+(n-1)*dn-1 mod n的值相同
定义dp[ i ][ j ]为前 i 个余数为 j 的方案数量
分为两种情况
A 最后一位为+a
B 最后一位为-b
以A为例,当第 i 位为+a时,令前 i-1 位值得和为c
可得c+i * a=j mod n
则c=j-i*a(mod n)
意义为 c加上第 i 项 i*a 的和 mod n等于j,B例则反之
在题目中,由于第一项为x,因此 i 值实为(n-i)
则dp[i][j]=dp[i - 1][get(j - a * (n - i), n)] + dp[i - 1][get(j + b * (n - i), n)];
其中为了避免出现负余数的想象,编写一个get函数取正模
import java.io.*;
import java.util.*;
public class Main {
static Scanner tab = new Scanner(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static int N = 1010;
//取正模
public static int get(int a,int b) {
return (a%b+b)%b;
}
public static void main(String[] args) throws IOException {
int mod=(int)1e8+7;
int n=tab.nextInt();
int s=tab.nextInt();
int a=tab.nextInt();
int b=tab.nextInt();
int dp[][]=new int [N][N];
dp[0][0]=1;//初始化
for(int i=1;i<n;i++) {
for(int j=0;j<n;j++) {
dp[i][j]=(dp[i - 1][get(j - a * (n - i), n)] + dp[i - 1][get(j + b * (n - i), n)]) % mod;
}
}
System.out.println(dp[n-1][get(s,n)]);
}
}
应该也属于背包或者组合的一种类型,涉及数学方面有点多,本来明白写下来感觉又懵了,网上这题解法很多,这里看的是y总视频的做法,建议看下视频讲的明白些