BSOJ 3022 又一类数字三角形--根据数据范围的优化+背包思想递推/搜索
来源:互联网 发布:网络电话录音 编辑:程序博客网 时间:2024/05/01 09:17
Description
假设有N个数写成一行,这行上面一行有N -1个数,第i数是第一行第i个数和第i+1个数的和。依次类推,最上面一行为第N行,有一个数。例如,4个数2,1,2,4形成如下结构:
15
6 9
3 3 6
2 1 2 4
我们称这种结构为NumberPyramid。两个NumberPyramid相同当且仅当对应位置上的数相同。
给出两个整数baseLength和top。计算出有多少个不同的仅包含正整数的NumberPyramid,使得NumberPyramid的最高的数为top,第一行有baseLength个数。由于答案可能过大,只需要输出模1,000,000,009的余数即可。
Input
第一行两个整数baseLength,top。
Output
一个整数,题目所求答案。
Sample Input
【样例输入1】 3 5
【样例输入2】 5 16
Sample Output
【样例输出1】 2
【样例输出2】 1
Hint
【数据范围】
对于30%的数据,top<=20,baseLength<=5。
对于100%的数据,2<=baseLength<=1,000,000,1<=top<=1,000,000。
这道题特别厉害..
容易发现,这就是一个加权杨辉三角,底层每一个数对顶层答案的贡献为c[n][i]*a[i],a[i]表示底层数字。
思路1:从top开始分割,用搜索来得到解的个数,加上适当的剪枝,可能拿得到30分。
思路2:考虑每个底层数字的贡献,我们发现这是一个n元的不定方程,每一项的系数为c[n][i],方程右边=top。
我们主要着手优化思路2。
这个数据够吓人,baselen长达100W,但是仔细分析下非常容易发现,一旦baselen大于一定的数值,top会大到惊人,我们举最小的例子:底层全都为1,那么top为2^(n-1),这样一来,一旦n>21,top的值就会超过100W,而题目数据给出的top范围恰恰是100W。
那么我们就可以把问题砍掉一大半:当n>21的时候,直接输出0,因为不存在这么大的top。
我们已经把原问题转化为了一个不超过21元的不定方程,当然这可不是一个数学问题(其实在系数已经确定的情况下可以直接暴力搜索了,但是top仍然高达100W,虽然说系数也不小,但枚举的量仍然庞大)。
进一步进行优化,其实没必要打到100W,前面都有提到,最小的top为(1<<(n-1)),所谓的更大无非是给杨辉三角加了一个系数,我们可以直接把top减去(1<<(n-1)),剩下的搜索也好,背包也罢,以杨辉三角为底数进行加倍枚举都能轻松通过所有数据。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define mod 1000000009
using namespace std;
inline int read()
{
int bj=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')bj=-1;
ch=getchar();
}
int ret=0;
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*bj;
}
int n,top,c[105][105]={0};
int f[1000005]={0};
void C()
{
for(int i=1;i<=100;i++)c[i][1]=c[i][i]=1;
for(int i=3;i<=20;i++)
{
for(int j=2;j<i;j++)
{
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
}
int main()
{
cin>>n>>top;
if(n>21)
{
cout<<0;
return 0;
}
C();
f[0]=1;
top-=(1<<(n-1));
for(int i=1;i<=n;i++)
{
for(int j=c[n][i];j<=top;j++)
f[j]=(f[j]+f[j-c[n][i]])%mod;
}
cout<<f[top];
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define mod 1000000009
using namespace std;
inline int read()
{
int bj=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')bj=-1;
ch=getchar();
}
int ret=0;
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*bj;
}
int n,top,c[105][105]={0};
int f[1000005]={0};
void C()
{
for(int i=1;i<=100;i++)c[i][1]=c[i][i]=1;
for(int i=3;i<=20;i++)
{
for(int j=2;j<i;j++)
{
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
}
int main()
{
cin>>n>>top;
if(n>21)
{
cout<<0;
return 0;
}
C();
f[0]=1;
top-=(1<<(n-1));
for(int i=1;i<=n;i++)
{
for(int j=c[n][i];j<=top;j++)
f[j]=(f[j]+f[j-c[n][i]])%mod;
}
cout<<f[top];
return 0;
}
这里用的背包思想,注意一下j的枚举顺序,要正着枚举。
搜索应该没问题吧?估计不会有人去写的..
这个题的优化特别厉害,也不是说想不到,认真思考下肯定能够有所发现,倒是最后的背包思想值得学习。(搜索赛高!)
0 0
- BSOJ 3022 又一类数字三角形--根据数据范围的优化+背包思想递推/搜索
- 递推 数字三角形
- 数字三角形——递归、递推、记忆化搜索
- 9.1数字三角形(记忆化搜索与递推)
- 【NOIP practice】BSOJ 1709 守望者的烦恼 矩阵快速幂优化递推
- HDU1005 一类递推矩阵优化
- BSOJ 2963:数字游戏 搜索+剪枝
- 动态规划之数字三角形(三种解法:递归,递推,记忆化搜索)
- 动态规划——数字三角形(递归or递推or记忆化搜索)
- 动态规划初步_数字三角形(递归,递推,数字化搜索)
- 【转】数字三角形-递推-动态规划
- 基础DP-递推-类数字三角形。
- 【NOIP practice】BSOJ 1947 编码 递推
- BSOJ:3801--隐藏指令 递推
- POJ1742 多重背包 递推关系优化
- BSOJ 4881 守望者的挑战---概率DP(更应该是递推)
- GG 数字三角形顺推。。。
- 数字三角形(搜索)
- python数据类型详解
- HDU 1106 排序(简单分类模拟)
- LeetCode 100. Same Tree
- Mac下使用mysql
- 爬动的蠕虫
- BSOJ 3022 又一类数字三角形--根据数据范围的优化+背包思想递推/搜索
- Atitit 编程语言原理与概论attilax总结 三大书籍总结
- TCP迭代服务器
- 《算法竞赛入门经典》第四章总结
- MySQL之MySQL5.7中文乱码
- 【非常高%】【codeforces 733A】Grasshopper And the String
- UE4 4.13 引擎bug
- 扒一扒 laravel的消息通知(上)
- LeetCode 171. Excel Sheet Column Number