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\n",ans%mod);
53 }
54 return 0;
55 }