欢迎访问我的新博客:http://www.milkcu.com/blog/
原文地址:http://www.milkcu.com/blog/archives/2014pa10.html
引言
这是2014年第五届蓝桥杯全国软件大赛预赛本科A组(C/C++组)第10题,也就是最后一题。
思路可以想得到,枚举和广度优先搜索,由于最后时间紧迫,简单的计数还没完成,谨以此文祭奠逝去的蓝桥杯。
题目描述
标题:波动数列
观察这个数列:
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。
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
分析
刚看这题,似乎摸不着头脑,细细欣赏,似乎还可以实现。
由于数据量可能很大,这里使用了long long类型。
输入给出了所有数的和s,假设该数列的第一个数为i,那么它的取值范围为[s - n * a, s + n * b]。
然后对枚举的每个数进行深度优先搜索,就可以得到结果。
考试时由于在main()函数内重复定义了变量cnt,和全局变量冲突,最后输出的答案一直是0,可惜没时间改了。
代码实现
#include <iostream>
using namespace std;
long long n, s, a, b;
long long sum;
long long cnt = 0;
long long mo = 100000007;
int dfs(long long nn, long long rn) {
//cout << "dfs " << nn << ", " << rn << endl;
sum += nn;
if(rn == 0) {
//cout << "sum " << sum << endl;
if(sum == s) {
sum -= nn;
//cout << "cnt" << endl;;
cnt++;
cnt %= mo;
return 1;
} else {
sum -= nn;
return 0;
}
}
dfs(nn + a, rn - 1);
dfs(nn - b, rn - 1);
sum -= nn;
}
int main(void) {
cin >> n >> s >> a >> b;
//dfs(2, 3);
for(long long i = s - n * a; i < s + n * b; i++) {
sum = 0;
dfs(i, n - 1);
}
cout << cnt << endl;
return 0;
}
(全文完)