有一个数列,它是由自然数组成的,并且严格单调上升。最小的数不小于S,最大的不超过T。现在知道这个数列有一个性质:后一个数相对于前一个数的增长率总是百分比下的整数(如5相对于4的增长率是25%,25为整数;而9对7就不行了)。现在问:这个数列最长可以有多长?满足最长要求的数列有多少个?
输入仅有一行,包含S和T两个数( 0<S<T≤200000 )。
30%的数据,0<S<T≤100 ;
100%的数据,0<S<T≤200000 。
输出有2行。第一行包含一个数表示长度,第二行包含一个数表示个数。
2 10
5 2
2 4 5 6 9以及2 4 5 8 10
因为最近经常接触动态规划,所以一下感觉应该是dp题目,dp基于这样的假设,对于第i个元素,以第
i个元素结尾的满足要求的最长数列a,以该数列倒数第二个元素结尾的最长数列就是a除掉第i个元素,这样讲有点模糊,我们不妨从归纳的思想考虑,如何减小问题的规模为n-1?
假设我们对于前n-1个元素都知道以其为结尾的最长数列,那么对于第n个元素,我们只要依次和前n-1个元素比较,是否符合题目要求,如果符合,那么第n个元素可以作为新的结尾接上去,找到这些新的数列中长度最长的,代码如下:
#include "stdio.h"
#include "string.h"
#include <string>
typedef long long ll;
int main()
{
int min,max;
int max_ans=0;
ll max_count=0;
scanf("%d%d",&min,&max);
int* result=new int[max+1];
ll* count=new ll[max+1];
for(int i=min;i<max+1;i++)
{
result[i]=1;
count[i]=1;
}
for(int i=min+1;i<=max;i++)
{
for(int j=min;j<i;j++)
{
if(((i-j)*100)%j==0)
{
if(result[i]<result[j]+1)
{
result[i]=result[j]+1;
count[i]=count[j];
}
else if(result[i]==result[j]+1)
{
count[i]+=count[j];
}
if(max_ans<result[j]+1)
{
max_ans=result[j]+1;
max_count=count[j];
}
else if(max_ans==result[j]+1)
{
max_count+=count[j];
}
}
}
}
printf("%d\n%d\n",max_ans,max_count);
return 0;
}
但是会超时,很显然这是一个O(n2)的算法,对于1-200000这种数据跑不出来,时间长,网上看到另外一个很好的解法,
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=200007;
int d[maxn];
ll cnt[maxn],time[maxn];
int main()
{
int s,t;
scanf("%d%d",&s,&t);
{
memset(cnt,0,sizeof(cnt));
int i,j,tmp,ans=1;
cnt[1]=t-s+1;
for(i=s;i<=t;i++)
{
d[i]=time[i]=1;
}
for(i=s;i<=t;i++)
{
for(j=1;j<=100;j++)
{
if( (i*j)%100 == 0)
{
tmp=i + i*j/100;
if(tmp<=t)
{
if(d[i]+1>d[tmp])
{
d[tmp]=d[i]+1;
time[tmp] = time[i];
}
else if(d[i]+1==d[tmp])
{
time[tmp] += time[i];
}
ans = max(ans,d[tmp]);
cnt[d[i]+1] += time[i];
}
}
}
}
printf("%d\n%lld\n",ans,cnt[ans]);
}
return 0;
}
思想不变,但是现在不是盲目的从当前数以前的所有数扫描,而是从逆向的思维考虑,我直接找到符合要求的这些数,对于不符合要求的数我不用考虑,这里原解法给到j=200,就是考虑到3i,这里我思考过,发现只要考虑到2i,即j=100即可,为什么呢?我们可以这样想,对于3i,其可以....i,2i,3i,这个解显然比...i,3i更优,而且可以验证对于2i到3i之间的数,都可以用i到2i之间的数构造更优的解,所以最多只需要考虑到2i,那么一定要考虑到2i吗?从理论上可能比较难想清楚,但是可以举一个实例验证,比如以2为开头,那么以4为结尾的数列最长为2,4,而4为2的两倍,所以如果小于2i,会出现错误,100恰到好处。
所以问题从O(n2)的复杂度压缩到O(n),多思考,多发现问题!
本文出自 “这与那” 博客,请务必保留此出处http://hereandthere.blog.51cto.com/7561107/1619911
原文地址:http://hereandthere.blog.51cto.com/7561107/1619911