一、大概题意:
给个数字N,会出现从1到N的序列,要求每次从1-N中任选某个数字,从序列中任选某些数去减去该数字,直至序列中所有数字为0。
二、解题思路:
找寻规律可发现,N 为偶数时,其所需要的步骤等于 1 + (N为 N/2时所需要的步骤);N为奇数时,与其前一个偶数所需要的步骤相同。
特别注意:本题需要计算到1e9,但是开1维dp数组只能开到1e8,所以从1e8-1e9需要单独计算。
三、举例:
N = 3,序列:1 2 3
所需最小步骤:①选则数字2,将序列中的2 -3减去该数字,此时序列中数字为0 1 1
②选择数字1,将序列中的2个1减去该书组,此时序列中数字全部为0
N = 6,序列:1 2 3 4 5 6
所需最小步骤:① 选则数字3,将序列中的3 -6减去该数字,此时序列中数字为0 1 1 2 2 3 (也可以将序列中的4 -6减去该数字,此时序列中数字为1 1 2 2 3 3 )
②剩下所需步骤与n= 3相同
N = 7,序列:1 2 3 4 5 6 7
所需最小步骤:① 选则数字4,将序列中的4 -7减去该数字,此时序列中数字为0 1 1 2 2 3 3
②剩下所需步骤与n= 3相同
四、附代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstring>
#include<string>
#include<set>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
const int maxn = 1e8;
typedef long long LL;
int n;
int dp[maxn];
void Table()
{
memset(dp,0,sizeof dp);
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i <= maxn; ++i)
{
if(i % 2 == 1)
{
dp[i] = dp[i-1];
}
else{
dp[i] = 1 + dp[i / 2];
}
}
}
void See()
{
for(int i = 1; i <= 100; ++i)
{
cout << dp[i] << " ";
if(i % 10 == 0){
cout << endl;
}
}
//134217728 28
//536870912 30
//268435456 29
}
int main()
{
Table();
while(scanf("%d",&n) != EOF)
{
if(n <= 100000000)
{
printf("%d\n", dp[n]);
}
if(n > 100000000 && n < 134217728)
{
cout << 27 << endl;
}
else if(n >= 134217728 && n < 268435456)
{
cout << 28 << endl;
}
else if(n >= 268435456 && n < 536870912)
{
cout << 29 << endl;
}
else if(n >= 536870912)
{
cout << 30 << endl;
}
}
}