A 大地魂力

时间限制 : - MS   空间限制 : - KB 
评测说明 : 1s,256m
问题描述

奶牛贝西认为,要改变世界,就必须吸收大地的力量,贝西把大地的力量称为魂力。要吸取大地的魂力就需要在地上开出洞穴来。
大地可以看成一个数轴,农夫约翰将不断地在大地上的选一个整数点来开一个洞穴,这个洞穴能分别从他左右两边第一个已经开出的洞穴吸取大地之魂力,吸取到的魂力数量等于对应洞穴的坐标。如果某一个方向没有洞穴,那么这个洞穴就无法从这个方向吸收大地之魂力。约翰可以在一个坐标点上开多个洞穴,每次吸收的大地之魂的数量都会累加。
现在按时间先后给出约翰的开洞的操作序列,约翰想知道他一共能吸收多少大地之魂。结果可能很大,你只需要告诉他模10^9+7 之后的结果。

输入格式

一行,5个整数 n, A, B, C, X1。其中n代表操作序列的长度。
由于n比较大,操作序列a将不通过输入数据给出,而是通过下列计算方法:
对于 2<=i<=nXi = ( A*(Xi-1)2 + B*Xi-1 + C ) mod (109+7)
对于操作序列a,它的第i项ai = (Xi mod n) + 1 1<=i<=n
ai就表示第i次操作打开的洞穴的坐标

输出格式

一个整数,表示计算结果

样例输入

5 2 3 2 3

样例输出

18

提示

操作序列为 4 5 2 3 5
操作1:坐标4位置打洞,吸取魂力0
操作2:坐标5位置打洞,吸取魂力4
操作3:坐标2位置打洞,吸取魂力4
操作4:坐标3位置打洞,吸取魂力6
操作5:坐标5位置打洞,吸取魂力4
总魂力18

n<=6000000 A,B,C,X1<=10^9+7

【题目分析】

对于 a[i]=i 的部分分,答案等于 1+2+……+n-1
对于 n<=1000 的部分分,每次插入之后暴力找前驱后继
对于 n<=100000 的部分分,用 set 维护当前的洞穴集合,每次插入之后用 set 寻找前驱后继
满分做法:把操作序列存起来, 记录下每个坐标点出现的次数, 然后把最后的序列建成链表,
倒着考虑操作,相当于每次删除一个点,直接用链表维护,复杂度 O(n)
/*
操作序列: 7210949104
*/

【参考代码】

 1 #include<cstdio>
 2 #include<cctype> 
 3 #define maxn 6000003
 4 using namespace std;
 5 int n, a, b, c, ans;
 6 int A[maxn], Cnt[maxn];
 7 char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;  
 8 struct Format {
 9     int Left, Right;
10 }List[maxn];
11 namespace Ironclad_Programming {
12     #define R register int
13     #define For(i, s, n) for (R i = s; i <= n; ++ i)
14     #define ll long long
15     #define Getch() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1 ++)
16     #define MOD 1000000007
17     inline int read() {  
18         int x = 0, f = 1; 
19         char ch = Getch();  
20         while(!isdigit(ch)){if (ch == '-')f = -1; ch = Getch();}  
21         while(isdigit(ch))x = x * 10 + (ch ^ 48), ch = Getch();  
22         return x * f;  
23     }  
24     void write(ll x) {  
25         if (x > 9) write(x / 10);  
26         *O ++ = x % 10 + '0';  
27     } 
28     void ini() {
29         n = read(), a = read(), b = read(), c = read(), A[1] = read();
30         For (i, 2, n)
31             A[i] = (((ll)a * A[i - 1] % MOD * A[i - 1] % MOD) % MOD + (ll)b * A[i - 1] % MOD + c) % MOD;
32         For (i, 1, n) {
33             A[i] = A[i] % n + 1;
34             ++ Cnt[A[i]];
35         }    
36     }
37     namespace solve {
38         int Last = 0;
39         void Link() {
40             For (i, 1, n)
41                 if (Cnt[i]) {
42                     List[i].Left = Last;
43                     List[Last].Right = i;
44                     Last = i;
45                 }
46         }
47         void Del_Back() {
48             for (R i = n; i; -- i) {
49                 (ans += (List[A[i]].Left + List[A[i]].Right) % MOD) %= MOD;
50                 if (!(-- Cnt[A[i]])) {
51                     List[List[A[i]].Left].Right = List[A[i]].Right;
52                     List[List[A[i]].Right].Left = List[A[i]].Left;
53                 }
54             }
55         }
56         void executive() {
57             Link();
58             Del_Back();
59             write(ans);
60         }
61     }
62     void Main() {
63         ini();
64         solve::executive();
65         fwrite(obuf, O - obuf, 1, stdout);
66     }
67     #undef R
68     #undef For
69     #undef ll
70     #undef Getch
71     #undef MOD
72 }
73 int main() {
74     Ironclad_Programming::Main();
75     return 0;
76 }
原文地址:https://www.cnblogs.com/Limbo-To-Heaven/p/11630976.html