您的位置:首页 > 运维架构

F(k)<(维护+枚举)\(找规律+递推+枚举)>

2016-05-30 21:26 453 查看

题意

小明有一个不降序列(f(1),f(2),f(3),……),f(k)代表在这个序列中大小是k的有f(k)个。我们规定f(n)的前12项如下图。


n 1 2 3 4 5 6 7 8 9 10 11 12

f(n) 1 2 2 3 3 4 4 4 5 5 5 6

现在给你一个n,你知道f(n)是多少吗?

多组测试数据

每组一个n(1<=n<=2000,000,000)。

###法一:正常情况下想的到。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long maxn=20000000;
int f[maxn];
int main ()
{
int nn,i;
long long j;
f[1]=1;
f[2]=2;
f[3]=2;
j=3;
for(i=3;j<=maxn-3;i++)
{
nn=f[i];
while(nn--&&j<=maxn)
{
f[++j]=i;
}
}
int n;
while(~scanf("%d",&n))
{
int ans=0,i;
for(i=1;ans<n;i++)
{
ans+=f[i];
}
printf("%d\n",i-1);
}
return 0;
}


法二:正常情况下想不到

因为n的最大范围是20亿,显然不能数组保存,而且时间也不允许,也很难发现什么规律。我们可以换个角度,既然要找的是f
的值,那么我们把f[x]=i时的最大x记录为 d[i] = x;
d[1] = 1
d[2] = 3
d[3] = 5
d[4] = 8
d[5] = 11


仔细推敲不难发现规律

从3起,d[i] = d[i-1] + find(i); find(i) = min(k) 当d[k]>=i时

find(i)也就是d数组中大于等于i的一项的最小值的下标。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=680000;
LL fuck[maxn];
int i;
int Find(int l,int r,int key)
{
int mid;
while(l<r)
{
mid=(l+r)/2;
if(fuck[mid]<key)
l=mid+1;
else
r=mid;
}
return l;
}
void init()
{
fuck[1]=1;fuck[2]=3;
for(i=3;i<=673365;i++){
fuck[i]=fuck[i-1]+Find(1,i-1,i);
}

}
int main ()
{
int n;init();
while(~scanf("%d",&n))
printf("%d\n",Find(1,i,n));
return 0;
}


STL的魅力

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=680000;
LL fuck[maxn];
int i;
void init()
{
fuck[1]=1;fuck[2]=3;
for(i=3;i<=673365;i++){
fuck[i]=fuck[i-1]+(lower_bound(fuck+1, fuck+i-1,i)-fuck);
}

}
int main ()
{
int n;init();
while(~scanf("%d",&n))
printf("%ld\n",(lower_bound(fuck+1, fuck+i,n)-fuck));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: