Description
有一个数列,它是由自然数组成的,并且严格单调上升。最小的数不小于S,最大的不超过T。现在知道这个数列有一个性质:后一个数相对于前一个数的增长率总是百分比下的整数(如5相对于4的增长率是25%,25为整数;而9对7就不行了)。现在问:这个数列最长可以有多长?满足最长要求的数列有多少个?(下称该类数列为增长数列)
Input Format
输入仅有一行,包含S和T两个数;0<S<T<S<T≤30%的数据,
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 810
问题分析:
此题符合动态规划问题的特点:
1. 对于[S, T]内的某个数 i,dp[ i ]表示从S到 i 之间最长增长数列的长度,同时需要一个n[ i ]表示以 i 结尾的最长增长数列的个数。dp[ i ]和n[ i ] 即为 i 的状态。
2. 确定 dp[ i ] 和 n[ i ]只与 dp[ j ] 与n[ j ] 有关 ( j < i && j >= S) 。
初始状态:dp[ i ] = n[ i ] = 1 ( i = S, S+1 ··· T );
递推关系:到这里有两种方法可以选择
1.人人为我型:对于数 i,从S 到 i-1循环寻找满足以 i 做结尾的最长增长数列dp[ j ],然后分dp[ j ]+1==dp[ i ]和dp[ j ]+1>dp[ i ] 进行递推:
dp[ j ]+1==dp[ i ] 此时最长增长数列长度不变,数量增多: n[ i]+=n [ j ];
dp[ j ]+1>dp[ i ] 最长增长数列长度更新,数量更新:dp[ i]=dp[ j ]+1; n[ i ]=n[ j ];
2.我为人人型:对于数 i,更新以tmp结尾( tmp 与 i 满足题目条件 ) 的状态值;递推分类同1.
比较两种方法,人人为我型的复杂度为n^2, 对于较大的数据可能会超时;我为人人型中由于 k% 中k 为整数,由tmp = i + (i*k)/100 满足条件的tmp 至多有100 个,故在复杂度方面更优;
代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int MAXNUM = 200020;
int dp[MAXNUM];
long long int n[MAXNUM];
int main()
{
int s, t, tmp, ans = 1;
long long int num = 0;
cin >> s >> t;
for(int i = s; i <= t; ++i)
dp[i] = n[i] = 1;
for(int i = s; i <= t; ++i)
for(int j = 1; j <= 100; ++j)
if((i*j)%100 == 0 && (i+(i*j)/100) <= t)
{
tmp = i + (i*j)/100;
if(dp[i]+1 > dp[tmp])
{
dp[tmp] = dp[i] + 1;
n[tmp] = n[i];
}
else if(dp[i]+1 == dp[tmp])
{
n[tmp] += n[i];
}
}
for(int i = s; i <= t; ++i)
{
if(dp[i] > ans)
{
ans = dp[i];
num = n[i];
}
else if(dp[i] == ans)
num += n[i];
}
cout << ans << endl << num;
return 0;
}
第一次写博客,如有错误,多多指正。