1012. 增長率問題
Description
有一個數列,它是由自然數組成的,並且嚴格單調上升。最小的數不小於S,最大的不超過T。現在知道這個數列有一個性質:後一個數相對於前一個數的增長率總是百分比下的整數(如5相對於4的增長率是25%,25爲整數;而9對7就不行了)。現在問:這個數列最長可以有多長?滿足最長要求的數列有多少個?
Input Format
輸入僅有一行,包含S和T兩個數( 0<S<T≤200000 )。
30%的數據,0<S<T≤100 ;
100%的數據,0<S<T≤200000 。
Output Format
輸出有2行。第一行包含一個數表示長度,第二行包含一個數表示個數。
Sample Input
2 10
Sample Output
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),多思考,多發現問題!