蓝桥杯---波动数列(dp)(背包)(待解决)
来源:互联网 发布:网络错误错误代码0031 编辑:程序博客网 时间:2024/05/21 07:46
问题描述
观察这个数列:
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。
开始的时候就感觉这道题应该没有那么简单,但是还是抱着试试看的心情做了一下,结果。。。就没有结果了,果断20%,剩下的全是TL,即使是之后的剪枝也是没什么作用(其实这也正常,粗略的算一下也会知道会超时的)
对于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。
开始的时候就感觉这道题应该没有那么简单,但是还是抱着试试看的心情做了一下,结果。。。就没有结果了,果断20%,剩下的全是TL,即使是之后的剪枝也是没什么作用(其实这也正常,粗略的算一下也会知道会超时的)
#include <iostream>#include <cstdio>using namespace std;int count=0,n,result,a,b,sum=0;bool sub(int i,int ceng){int ss=(2*i+(ceng-1)*-b)*ceng/2;return sum+ss<=result;}bool add(int i,int ceng){int ss=(2*i+(ceng-1)*a)*ceng/2;return sum+ss>=result ;}void dfs(int i,int cou){sum+=i;int temp=count;if(sum==result&&cou==n) { count++; } //cout<<i<<' ';if(cou>=n){ sum-=i; return ;} if(sub(i-b,n-cou))//如果剩下的全部为减法都不能成立的话就直接不用继续深搜下去了 //但是这样的优化好像是杯水车薪,依然超时 dfs(i+a,cou+1);//if(count!=temp) cout<<i<<' '; //temp=count; if(add(i+a,n-cou))//与上同理 dfs(i-b,cou+1); //if(count!=temp) cout<<i<<' ';sum-=i;return;}int main(){ scanf("%d%d%d%d",&n,&result,&a,&b); int top=(result*2/n-(n-1)*-b)/2, bott=(result*2/n-(n-1)*a)/2; cout<<top<<' '<<bott<<endl; for(int i=bott; i<=top; i++){ // cout<<"底数为"<<i<<" "<<sum<<endl; dfs(i,1); // cout<<endl; } cout<<count<<aaa<<endl; return 0;}
最后才知道是动态的一道题,不过好像还是有点不太懂,之后整理吧。。。
找到了下面的一个代码:(找了好长时间才找到这么一个100%AC的,但是好像还是有点不太懂)
http://blog.csdn.net/quzhongrensan511/article/details/23156363
原题可化为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[n][i],避免重复计算;前i个货物最多只能达到i*(i+1)/2的体积,所以大于这个数值的部分没有必要计算。具体的请看代码,其实就这么几行。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#define MAXN 1100#define MOD 100000007using 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;}
0 0
- 蓝桥杯---波动数列(dp)(背包)(待解决)
- 蓝桥杯 波动数列 DP背包
- 蓝桥杯 波动数列(01背包方案数)
- 历届试题 波动数列 (DP)
- 蓝桥杯 波动数列 (DP&滚动数组 好题)
- 蓝桥杯之波动数列(未解决:运行超时)
- 蓝桥杯 历届试题 波动数列 DP 01背包 滚动数组
- 背包DP——波动数列
- 历届试题 波动数列 (未完成)
- POJ1661 Help Jimmy DP (待解决)
- 波动数列背包版.java
- NYOj题目370波动序列(dp)
- 波动数列 - 蓝桥杯
- 蓝桥杯 波动数列 【未完成】
- 蓝桥杯:波动数列
- 蓝桥杯 波动数列
- 背包问题(待补充)
- 01背包问题(DP解决)
- android 录像,摄影自定义保存的文件名称
- Smarty模板缓存应用
- C语言指针的赋值问题
- POI对EXCEL的操作【重点:如何设置CELL格式为文本格式】
- C++课堂作业
- 蓝桥杯---波动数列(dp)(背包)(待解决)
- win7下安装Ubuntu实现双在系统
- 基于STM32的多功能MP3设计 元件清单
- HDU1004 Let the Balloon Rise【字典树】
- POJ 1001 Exponentiation 高精度乘法
- topcoder srm656 1000分题(div2)
- 网页竖排文字的实现——只需要CSS
- ZOJ 1091 POJ 2935 Knight Moves BFS水题
- arm汇编指令WFI和WFE