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 }
原文地址:https://www.cnblogs.com/937337156Zhang/p/6020751.html