题目描述:给定一串数字1~n,每次可以选取任意个数字对他们减去任意一个数字x,求将这n个数全部减为0所需的最小处理次数。
思路:我做时算是在边推边找规律吧,推到n为12才突然反应过来:F(n) = F(n / 2) + 1。如1 2 3 4 5 6 7首先将4 5 6 7分别减去4得到1 2 3 0 1 2 3此时相当于将原来的串1 2 3 4 5 6 7 变成了1 2 3,然后将所有的2 3减去2,得到1 0 1 0 1 0 1,最后再将所有的1减去1得到0 0 0 0 0 0 0。原本想用数组保存结果直接输出的,结果发现n最大为1e9,数组开不下,又想了想其实就是分治递归的思想每次给定一个n直接递归求解即可。不过为了节约时间,还是用数组储存了部分结果,其实是没有必要的。直接递归求解时间为30ms,而开数组是340ms,反而更耗时。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 2 * 1e8 + 10;
const int maxt = 1e6 + 10;
const int mod = 10000007;
const int dx[] = {1, -1, 0, 0, -1, -1, 1, 1};
const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const double inf = 0x3f3f3f3f;
ll num[maxn];
int n, m, k;
ll solve(int n){
if(n == 1) return 1;
return solve(n / 2) + 1;
}
int main(){
while(scanf("%d", &n) != EOF){
ll ans = solve(n);
printf("%lld\n", ans);
}
return 0;
}
下面这段代码,原本想节省时间的,结果反而是多此一举了,更耗时。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 2 * 1e8 + 10;
const int maxt = 1e6 + 10;
const int mod = 10000007;
const int dx[] = {1, -1, 0, 0, -1, -1, 1, 1};
const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const double inf = 0x3f3f3f3f;
ll num[maxn];
int n, m, k;
void init(){
num[0] = 0;
num[1] = 1;
num[2] = 2;
for(int i = 3; i < maxn; ++i){
num[i] = num[i / 2] + 1;
}
}
ll solve(int n){
if(n < maxn) return num[n];
return solve(n / 2) + 1;
}
int main(){
init();
while(scanf("%d", &n) != EOF){
if(n < maxn)printf("%lld\n", num[n]);
else{
ll ans = solve(n);
printf("%lld\n", ans);
}
}
return 0;
}