@ 蓝桥杯 练习系统 历届试题 PREV-30
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
观察这个数列:
1 3 0 2 -1 1 -2 …
这个数列中后一项总是比前一项增加2或者减少3。
栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?
输入格式
输入的第一行包含四个整数 n s a b,含义如前面说述。
输出格式
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。
测试样例1
Input:
4 10 2 3
Output:
2
Explanation:
这两个数列分别是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。
ACcode:
import java.io.*;
import java.util.*;
public class Main {
static final int mod = 100000007;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, 128);
int n, a, b, sum, cnt = 0, dp[];
long m, ab;
n = in.nextInt(); m = in.nextInt();
a = in.nextInt(); b = in.nextInt();
sum = (n - 1) * n / 2;
dp = new int[sum + 1];
m += sum * (long)b;
ab = a + b;
dp[0] = 1;
for (int i = 1; i < n; i++)
for (int j = sum; j >= i; j--)
dp[j] = (dp[j] + dp[j - i]) % mod;
for (int i = 0; i <= sum; i++)
if ((m - i * ab) % n == 0) cnt = (cnt + dp[i]) % mod;
System.out.print(cnt);
}
static class InputReader {
byte[] buff;
int next, len;
InputStream in;
InputReader(InputStream in) { this(in, 1024); }
InputReader(InputStream in, int buffSize) {
this.buff = new byte[buffSize];
this.in = in;
}
int read() {
if (next >= len)
try {
next = 0;
len = in.read(buff);
if (len == -1) return -1;
} catch (IOException e) {}
return buff[next++];
}
int nextInt() {
int n = 0, c = read();
while (c < '0' || c > '9') c = read();
while (c >='0' && c <='9') {
n = n * 10 + (c & 0xf);
c = read();
}
return n;
}
}
}
我知道这么写必过不了,但我有了这个思路后我就知道这应该是道动态规划题,算写着玩吧,等上完课研究会儿
import java.io.*;
public class Main {
static int n, m, a, b, cnt;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, 128);
n = in.nextInt();
m = in.nextInt();
a = in.nextInt();
b = in.nextInt();
dfs(1, 0, 0);
System.out.print(cnt);
}
static void dfs(int d, int s, int sum) {
if (d == n) {
if ((sum + s + m) % n == 0) cnt++;
} else {
dfs(d + 1, s + a, sum + s);
dfs(d + 1, s - b, sum + s);
}
}
static class InputReader {
byte[] buff;
int next, len;
InputStream in;
InputReader(InputStream in) { this(in, 1024); }
InputReader(InputStream in, int buffSize) {
this.buff = new byte[buffSize];
this.in = in;
}
int read() {
if (next >= len)
try {
next = 0;
len = in.read(buff);
if (len == -1) return -1;
} catch (IOException e) {}
return buff[next++];
}
int nextInt() {
int n = 0, c = read();
while (c < '0' || c > '9') c = read();
while (c >='0' && c <='9') {
n = n * 10 + (c & 0xf);
c = read();
}
return n;
}
}
}
我回来了
可以说,任何数据如果怎么来的,就怎么放到程序里面去,那不超时或者爆堆,那就是数据太小了
写的我不知所云,但总的来说就是尽可能的总结规律压缩数据
以测试数据为例:
x = 2 | x = 7 |
---|---|
x + a | x - b |
x + a - b | x - b - b |
x + a - b + a | x - b - b - b |
markdown表格确实跟shi一样
到这里想必你就能明白 只能也必须选择 +a,-b 的用意了
a,b 任意组合他们的数量都会出现 n * (n - 1) / 2 次
这里我们将它记为 sum
如果出现 k 次 a,那就代表出现 sum - k 次 b
但最开始的搜索代码里,a与b的能构成不同组合的数量在 n2,所以现在问题就变成了
通过 a 的数量来计算它们能构成不同组合的个数
通过 k、m、sum 的和与 n 取模,并统计结果
统计组合个数套个 01 背板模板就行
int sum = (n - 1) * n / 2;
int[] dp = new int[sum + 1];
dp[0] = 1;
for (int i = 1; i < n; i++)
for (int j = sum; j >= i; j--)
dp[j] = (dp[j] + dp[j - i]) % mod;
计算与统计则是
for (int i = 0, j = sum; i <= sum; i++, j--)
if ((m + a * i - b * j) % n == 0) cnt = (cnt + dp[i]) % mod;
成品 (AC) :
import java.io.*;
import java.util.*;
public class Main {
static final int mod = 100000007;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, 128);
int n = in.nextInt(), m = in.nextInt();
long a = in.nextInt(), b = in.nextInt();
int sum = (n - 1) * n / 2, dp[] = new int[sum + 1], cnt = 0;
dp[0] = 1;
for (int i = 1; i < n; i++)
for (int j = sum; j >= i; j--)
dp[j] = (dp[j] + dp[j - i]) % mod;
for (int i = 0, j = sum; i <= sum; i++, j--)
if ((m + a * i - b * j) % n == 0) cnt = (cnt + dp[i]) % mod;
System.out.print(cnt);
}
static class InputReader {
byte[] buff;
int next, len;
InputStream in;
InputReader(InputStream in) { this(in, 1024); }
InputReader(InputStream in, int buffSize) {
this.buff = new byte[buffSize];
this.in = in;
}
int read() {
if (next >= len)
try {
next = 0;
len = in.read(buff);
if (len == -1) return -1;
} catch (IOException e) {}
return buff[next++];
}
int nextInt() {
int n = 0, c = read();
while (c < '0' || c > '9') c = read();
while (c >='0' && c <='9') {
n = n * 10 + (c & 0xf);
c = read();
}
return n;
}
}
}
最后优化一点直接丢上面了
ps:从结果来看优化了个激素拔刀,大概是因为耗时主要在 long 取模上把