第五届蓝桥杯C/C++本科A组初赛波动数列解题报告
2014-04-08 07:12
393 查看
原题可化为nx+(n-1)p(1)+(n-2)p(2)+…+p(n)=s,其中n为数列长度,x为初值,p(i)={a,-b}。本题的目标是给出不同的p序列,使得等式成立并且x为整数。自然而然可以想到枚举的方法,给出不同的序列,令t=s-Σi*p(n-i),若t%n==0则是一种可取的方案。直接枚举肯定会超时,所以需要进一步考虑。注意到,a和b的总数为n(n-1)/2个(所有p前系数的和),所以我们只需要枚举a的个数,将t修改为t=s-ca-(n(n-1)/2-c)b,c为枚举数,0<=c<=n(n-1)/2。
当然满足条件的c的个数并不是我们想要的,因为给定一个c,存在多种组合方式。但是可以发现,每个c都是由1~n-1中若干元素组成的。于是问题转化为求容量为c的01背包的方案数。对于本题,可以写为:(f[i][j]为前i个物体构成j体积的方案数,第i个物体的体积为i)
f[i][j]=f[i-1][j], i>j
f[i-1][j]+f[i-1][j-i], j>=i
注意到递推式只和前一状态有关,故可以使用滚动数组;根据定义,可以预先算出每一个f
[i],避免重复计算;前i个货物最多只能达到i*(i+1)/2的体积,所以大于这个数值的部分没有必要计算。具体的请看代码,其实就这么几行。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAXN 1100
#define MOD 100000007
using namespace std;
int F[2][MAXN*MAXN];
int e = 0;
long long n,s,a,b;
int cnt = 0;
void calc(int elem)
{
int i,j;
memset(F,0,sizeof(F));
F[e][0]=1;
for(i=1;i<n;i++)
{
e=1-e;
for(j=0;j<=i*(i+1)/2;j++)
{
if(i>j)
F[e][j]=F[1-e][j];
else
F[e][j]=(F[1-e][j]+F[1-e][j-i])%MOD;
}
}
}
int main()
{
scanf("%I64d%I64d%I64d%I64d",&n,&s,&a,&b);
long long i,t;
calc(n*(n-1)/2);
for(i=0; i<=n*(n-1)/2; i++)
{
t = s - i*a + (n*(n-1)/2-i)*b;
if(t%n==0)
cnt = (cnt+F[e][i])%MOD;
}
printf("%d",cnt);
return 0;
}
当然满足条件的c的个数并不是我们想要的,因为给定一个c,存在多种组合方式。但是可以发现,每个c都是由1~n-1中若干元素组成的。于是问题转化为求容量为c的01背包的方案数。对于本题,可以写为:(f[i][j]为前i个物体构成j体积的方案数,第i个物体的体积为i)
f[i][j]=f[i-1][j], i>j
f[i-1][j]+f[i-1][j-i], j>=i
注意到递推式只和前一状态有关,故可以使用滚动数组;根据定义,可以预先算出每一个f
[i],避免重复计算;前i个货物最多只能达到i*(i+1)/2的体积,所以大于这个数值的部分没有必要计算。具体的请看代码,其实就这么几行。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAXN 1100
#define MOD 100000007
using namespace std;
int F[2][MAXN*MAXN];
int e = 0;
long long n,s,a,b;
int cnt = 0;
void calc(int elem)
{
int i,j;
memset(F,0,sizeof(F));
F[e][0]=1;
for(i=1;i<n;i++)
{
e=1-e;
for(j=0;j<=i*(i+1)/2;j++)
{
if(i>j)
F[e][j]=F[1-e][j];
else
F[e][j]=(F[1-e][j]+F[1-e][j-i])%MOD;
}
}
}
int main()
{
scanf("%I64d%I64d%I64d%I64d",&n,&s,&a,&b);
long long i,t;
calc(n*(n-1)/2);
for(i=0; i<=n*(n-1)/2; i++)
{
t = s - i*a + (n*(n-1)/2-i)*b;
if(t%n==0)
cnt = (cnt+F[e][i])%MOD;
}
printf("%d",cnt);
return 0;
}
相关文章推荐
- 2014 第五届蓝桥杯预赛c/c++本科B组 解题报告
- 2014年第五届蓝桥杯预赛 C/C++本科B组 快速解题思路及报告(完整版,4.9修订)
- 第二届蓝桥杯C++本科B组初赛解题报告
- 第五届蓝桥杯软件大赛C/C++本科B组解题报告
- 第五届蓝桥杯软件大赛C/C++本科B组决赛解题报告
- 2014年蓝桥杯预赛 C/C++本科B组 解题报告 史丰收速算
- 第四届蓝桥杯C++本科B组决赛解题报告
- 2014年蓝桥杯预赛 C/C++本科B组 解题报告 打印图形
- 2014年蓝桥杯预赛 C/C++本科B组 解题报告 (本人写的)
- 第三届蓝桥杯C++本科B组决赛解题报告(更新中)
- 第二届蓝桥杯C++本科B组决赛解题报告
- 第四届蓝桥杯C++本科B组预赛解题报告
- 2014年蓝桥杯预赛 C/C++本科A组 解题报告 史丰收速算
- 第三届蓝桥杯C++本科B组决赛解题报告(更新中)
- 运行时间排列第四届蓝桥杯C++本科B组解题报告
- 2013蓝桥杯预赛C/C++本科B组解题报告
- 第四届蓝桥杯C++本科B组预赛解题报告
- 2013 蓝桥杯第四届c/c++B组 解题报告(完全解决第四题,代码有点长....)
- 第五届蓝桥杯C++A组 波动数列
- 第五届蓝桥杯省赛解题报告--神奇算式