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


    题意

     小明有一个不降序列(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
    ",i-1);
        }
        return 0;
    }

    法二:正常情况下想不到

    因为n的最大范围是20亿,显然不能数组保存,而且时间也不允许,也很难发现什么规律。我们可以换个角度,既然要找的是f[n]的值,那么我们把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
    ",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
    ",(lower_bound(fuck+1, fuck+i,n)-fuck));
        return 0;
    }
    想的太多,做的太少。
  • 相关阅读:
    Android中从一个Activity跳转到另一个Activity所经历的生命周期
    Android五种数据存储方式
    Android的Activity启动方式(模式)
    个人笔记--activity--basic
    activity的生命周期
    gradle和maven的区别
    node是什么
    npm是什么
    激光雷达与毫米波雷达区别讲解
    VSLAM技术框架详述
  • 原文地址:https://www.cnblogs.com/pealicx/p/6115633.html
Copyright © 2020-2023  润新知