• NOIP模拟题——nan



    【问题描述】
    我们 有一个序列 ,现在他里面有三个数 1,2,2。我们从第三个数开始考虑:
    1、第三个数是 2,所以我们在序列后面写 2个3,变成 1,2,2,3,3。
    2、第四个数是 3,所以我们在序列后面写 3个4,变成 1,2,2,3,3,4,4,4。
    那么你可以看到 ,这个序列应该是 1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,…。
    如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数 如果我们设一个数x最后出现的位置为last(x),那么现在我希望知道last(last(x))等于多少 。
    【输入格式】
    第一行 一个整数T,代表数据组数。
    接下来T行每行一个整数x。
    【输出格式】
    T行,每行一个整数 ,代表last(last(x)) mod (109+7)的值 。
    【样例输入】
    3
    3
    10
    100000
    【样例输出】
    11
    217
    507231491
    【数据规模与约定】
    对于 30%的数据, 1≤N≤10³。
    对于 60%的数据 ,1≤N≤106。
    对于 100%的数据 ,1≤N≤109,1≤T≤2×10³。

    看到题直接懵B。。10的9次方

    然后写了一个暴力程序,直接算出1到1000000的last,发现只能过30%

    部分暴力代码:

     1 last[1]=1,last[2]=3;int q=2;
     2 a[1].left=a[1].right=1;
     3 a[2].left=2;a[2].right=3;
     4 for(int i=3;i<=1400000;i++)
     5 {
     6     last[i]=last[i-1]+q;
     7     a[i].right=last[i];
     8     a[i].left=last[i-1]+1;
     9     if(i>=last[temp])
    10     {
    11         q++;temp++;
    12     }
    13 }

    搞了很久才明白60%是怎么做的:

    首先打表找出last和last(last) (这里只写10组):

    x                1    2    3    4    5     6     7    8      9      10

    a[x]               1    2    2    3    3     4     4    4       5      5 

    last(x)    1    3    5    8    11   15   19  23    28    33

    last(last(x))    1    5    11  23  38   62   90  122  167  217

    撒子也不晓得…………

    outfutr2330讲解过后才发现神奇算法:算last(last(x))-last(last(x-1)):

    last(last(x))-last(last(x-1))      1  4  6  12  15  24  28  32  45  50

    又可以写成:                         1*1   2*2  2*3   3*4   3*5    4*6    4*7    4*8    4*9    5*10

    可以看出,后面的数1~10就等于i,而前面的数刚好就是a[x]

    于是预处理的时候就将各个分块(a[x]相同的为一块)的left和right保存起来,这样依次用等差序列求和公式就能得出ans了

    至于n在中间的情况(如last(last(7)),就用a[4]的right和n(7)做比较,n小则只加上left到n的等差序列,这样就可以过60%的数据

    至于100%的数据,要用到前缀和和二分的方法:前缀和求前面连续分块的和,二分求出离n最近的a[rightn].right的编号rightn,

    再加上后面的等差序列(同上),可以算出大约第130万个分块的长度超过了1e9,所以二分是可行的。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 using namespace std;
     5 const long long maxn=1400000+7;
     6 const long long mod=1e9+7;
     7 int n,t;
     8 long long last[maxn];
     9 long long llst[maxn];
    10 long long k[maxn];
    11 struct node{
    12     long long left,right;
    13 }a[maxn];
    14 long long temp=2;
    15 int main()
    16 {
    17     freopen("nan.in","r",stdin);
    18     freopen("nan.out","w",stdout);
    19     last[1]=1,last[2]=3;int q=2;
    20     a[1].left=a[1].right=1;
    21     a[2].left=2;a[2].right=3;
    22     for(int i=3;i<=1400000;i++)
    23     {
    24         last[i]=last[i-1]+q;
    25         a[i].right=last[i];
    26         a[i].left=last[i-1]+1;
    27         if(i>=last[temp])
    28         {
    29             q++;temp++;
    30         }
    31     }
    32     
    33     for(int i=1;i<=1400000;i++)
    34     {
    35         k[i]=k[i-1]+(a[i].right-a[i].left+1)*i*(a[i].left+a[i].right)/2%mod;
    36         k[i]%=mod;
    37     }
    38     scanf("%d",&t);
    39     long long ans=0;
    40     for(int i=1;i<=t;i++)
    41     {
    42         int n;scanf("%d",&n);
    43         int leftn=1,rightn=1400000;
    44         while(leftn<=rightn)
    45         {
    46             int mid=(leftn+rightn)>>1;
    47             if(a[mid].right<n)leftn=mid+1;
    48             else rightn=mid-1;
    49         }
    50         ans=k[rightn];
    51         ans+=(rightn+1)*(n-a[rightn].right)*(a[rightn+1].left+n)/2%mod;
    52         printf("%I64d
    ",ans%mod);
    53     }
    54     return 0;
    55 }
  • 相关阅读:
    MT7601 AP模式移植
    dhcp server 移植记录
    MT7601 WG209模块驱动移植,并连接路由器
    git 忽略文件
    关于中文--Unicode之间互相转换流程的说明
    将文字拆成拼音得到首字母(返回多音字)
    Javascript 汉字转首字母的拼音 js文件(支持多音字的选择)
    如何使用netstat –ano|findstr “port”命令?
    notepad++如何修改主题
    Notepad++ 更换主题
  • 原文地址:https://www.cnblogs.com/937337156Zhang/p/6020751.html
Copyright © 2020-2023  润新知