题意:

写下一组数,

1.先写1,2,2。

2.第三个数字是2,所以在后面写两个3。

3.第四个数字是3,所以在后面三个4。

4.像这样可以得到1,2,2,3,3,4,4,4,5,5,5,6,6,6,6。

给出一个数字n,假设这个n的最后出现的位置为p,求p最后出现的位置。其中

思路:

可以找出规律要求的,其中为原数列的前缀和,可以写几项。

由此可以知道,其中表示原数列。

因为原数列可以根据值分成几块,所以预处理出

:原数列,

:i最后一次出现的位置,

:第个数的

这些东西就可以了,对于一个n其他多余的要加的东西可以在块内进行。

所以二分一下每个n在哪一块里再把前面的和块内的加起来就可以了。

找规律的题做法直接说出来的确有点抽象,这种东西还是要自己手推一下…

找规律的题分块的确是一种写法。

代码:

#define MOD 1000000007
typedef long long ll;
int cnt;
ll f[1000010];
ll locr[1000010];//最后一次出现的位置
ll pre[1000010];//第locr[i]个数的值
int init()
{
    f[1]=1;f[2]=2;f[3]=2;
    int cur=3;
    for(ll i=3;cur<=440000;i++)
    {
        for(int j=0;j<f[i];j++)
            f[++cur]=i;
    }
    /*for(int i=1;i<=20;i++)
        printf("%lld ",f[i]);
    printf("\n");*/
    locr[1]=1;
    for(int i=2;;i++)
    {
        locr[i]=locr[i-1]+f[i];
        if(locr[i]>1e9)
        {
            cnt=i-1;
            break;
        }
    }
    /*for(int i=1;i<=10;i++)
        printf("%lld ",locr[i]);
    printf("\n");*/
    pre[1]=1;
    for(int i=2;i<=cnt;i++)
        pre[i]=(pre[i-1]+((((locr[i-1]+1+locr[i])*(locr[i]-locr[i-1]))%MOD*500000004ll)%MOD*i)%MOD)%MOD;
    /*for(int i=1;i<=10;i++)
        printf("%lld ",pre[i]);
    printf("\n");*/
}
int main()
{
    init();
    //printf("%d\n",cnt);
    int t;
    ll n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        int pos=upper_bound(locr+1,locr+1+cnt,n)-locr;
        pos--;
        //printf("%d\n",pos);
        ll ans=0;
        ans=(ans+pre[pos])%MOD;
        ans=(ans+((((locr[pos]+1+n)*(n-locr[pos]))%MOD*500000004ll)%MOD*(pos+1))%MOD)%MOD;
        printf("%lld\n",ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

HDU6370 思维+tarjan缩点 Previous
HDU5446 lucas定理+中国剩余定理+快速乘 Next