[题解]洛谷比赛『期末考后的休闲比赛2』

Posted 阿波罗2003

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解]洛谷比赛『期末考后的休闲比赛2』相关的知识,希望对你有一定的参考价值。

前言(在题解前面瞎扯的话)

  这场比赛已经结束了有几天,但我各种忙,虽然AK但还是没来得及写题解。(我才不会告诉你我跑去学数据结构了)


T1 区间方差

(就不贴题好了)

  首先可以推公式(我们可以知道,线段树然而并不能通过初中学过的方差公式在log(L)内求出方差):

(s2表示方差,L表示区间长度,xi表示区间的每一项,最后一个x上画了一根线表示这些数据的平均数)

二项式定理完全平方公式可得:

 

再次展开:

另外,再代入以下这个

得到了:

然后继续吧。。 

然后duang地一声合并同类项,于是我们得到了:

  然后可以高兴地发现,和 和 平方和都是线段树的拿手好戏,然而按照这么写估计只能过几个点。

很明显平方和肯定会超long long,难不成还要写一个高精度?

  仔细读读题,然后就发现可以模一个1e9+7。然后处处取模(笑),最后就能够水掉这道水题了。

  至于求逆元,可以用在线算法,扩展欧几里得、快速幂(好像是基于欧拉定理),也可以用线性推逆元预处理所有可能用到的逆元。

Code(线段树)

  1 /**
  2  * luogu.org
  3  * Problem#2005
  4  * Accepted
  5  * Time:965ms / 691ms
  6  * Memory:18601k / 18601k
  7  */
  8 #include<iostream>
  9 #include<fstream>
 10 #include<sstream>
 11 #include<cstdio>
 12 #include<cstdlib>
 13 #include<cstring>
 14 #include<ctime>
 15 #include<cctype>
 16 #include<cmath>
 17 #include<algorithm>
 18 #include<stack>
 19 #include<queue>
 20 #include<set>
 21 #include<map>
 22 #include<vector>
 23 using namespace std;
 24 typedef bool boolean;
 25 #define smin(a, b)    (a) = min((a), (b))
 26 #define smax(a, b)    (a) = max((a), (b))
 27 template<typename T>
 28 inline void readInteger(T& u){
 29     char x;
 30     int aFlag = 1;
 31     while(!isdigit((x = getchar())) && x != \'-\' && x != -1);
 32     if(x == -1)    return;
 33     if(x == \'-\'){
 34         x = getchar();
 35         aFlag = -1;
 36     }
 37     for(u = x - \'0\'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - \'0\');
 38     ungetc(x, stdin);
 39     u *= aFlag;
 40 }
 41 
 42 const int moder = 1000000007;
 43 
 44 template<typename T1, typename T2>
 45 class Pair{
 46     public:
 47         T1 x;
 48         T2 y;
 49         Pair(T1 x, T2 y):x(x), y(y){    }
 50         Pair operator +(Pair another){
 51             return Pair(x + another.x % moder, y + another.y % moder);
 52         }
 53 };
 54 
 55 typedef class TreeNode{
 56     public:
 57         int sum;
 58         int sum2;
 59         int from, end;
 60         TreeNode* left, *right;
 61         TreeNode(long long sum, int from, int end):from(from), end(end), left(NULL), right(NULL), sum(sum){
 62             sum2 = sum * sum % moder;
 63         }
 64         void pushUp(){
 65             this->sum = this->left->sum + this->right->sum;
 66             this->sum %= moder;
 67             this->sum2 = this->left->sum2 + this->right->sum2;
 68             this->sum2 %= moder;
 69         }
 70 }TreeNode;
 71 
 72 typedef class SegTree{
 73     public:
 74         TreeNode* root;
 75         
 76         SegTree():root(NULL){    }
 77         SegTree(int size, int* val){
 78             build(root, 1, size, val);
 79         }
 80         
 81         void build(TreeNode*& node, int from, int end, int* val){
 82             node = new TreeNode(0, from, end);
 83             if(from == end){
 84                 node->sum = val[from];
 85                 node->sum2 = (int)(val[from] * 1LL * val[from] % moder);
 86                 return;
 87             }
 88             int mid = (from + end) >> 1;
 89             build(node->left, from, mid, val);
 90             build(node->right, mid + 1, end, val);
 91             node->pushUp();
 92         }
 93         
 94         void update(TreeNode*& node, int index, int val){
 95             if(node->from == index && node->end == index){
 96                 node->sum = val;
 97                 node->sum2 = (int)(val * 1LL * val % moder);
 98                 return;
 99             }
100             int mid = (node->from + node->end) >> 1;   
101             if(index <= mid)    update(node->left, index, val);
102             else update(node->right, index, val);
103             node->pushUp();
104         }
105         
106         Pair<long long, long long> query(TreeNode*& node, int from, int end){
107             if(node->from == from && node->end == end){
108                 return Pair<long long, long long>(node->sum, node->sum2);
109             }
110             int mid = (node->from + node->end) >> 1;
111             if(end <= mid)    return query(node->left, from, end);
112             if(from > mid)    return query(node->right, from, end);
113             return query(node->left, from, mid) + query(node->right, mid + 1, end);
114         }
115         
116 }SegTree;
117 
118 /*
119 int pow_mod(int x, int pos){
120     if(pos == 1)    return x;
121     int temp = pow_mod(x, pos / 2);
122     if(pos & 1)    return (int)(temp * 1LL * temp % moder * x % moder);
123     return (int)(temp * 1LL * temp % moder);
124 }
125 */
126 
127 void gcd(int a, int b, int& d, int& x, int& y){
128     if(b == 0){
129         d = a;x = 1;y= 0;
130     }else{    gcd(b, a % b, d, y, x); y -= x * (a / b);    }
131 }
132 
133 int getInv(int a, int n){
134     int d, x, y;
135     gcd(a, n, d, x, y);
136     return (x + n) % n;
137 }
138 
139 int n, m;
140 SegTree st;
141 int* initer;
142 
143 inline void init(){
144     readInteger(n);
145     readInteger(m);
146     initer = new int[(const int)(n + 1)];
147     for(int i = 1; i <= n; i++)
148         readInteger(initer[i]);
149     st = SegTree(n, initer);
150 }
151 
152 inline void solve(){
153     int op, a, b;
154     while(m--){
155         readInteger(op);
156         readInteger(a);
157         readInteger(b);
158         if(op == 1){
159             st.update(st.root, a, b);
160         }else if(op == 2){
161             Pair<long long, long long> p = st.query(st.root, a, b);
162             long long L = b - a + 1;
163 //            long long inv = pow_mod(L * L % moder, moder - 2);
164             int inv = getInv(L * L % moder, moder);
165             long long fm = (L * (p.y % moder) % moder - p.x * p.x % moder + moder) % moder;
166             long long ans = fm * inv % moder;
167             printf("%d\\n", (int)ans);
168         }
169     }
170 }
171 
172 int main(){
173     init();
174     solve();
175     return 0;
176 }

  不过这道题只有单点修改,那么,可以考虑用树状数组。树状数组的常数比线段树小这是家喻户晓的事情(两者理论时间复杂度一样)。

  另外鉴于洛谷鬼蓄的评测机,把某些只超一点点的取模符号改成三目运算符,就快了100多ms(吐血)。

  由于我比较懒,又赶去学Splay,所以没有来得急写。


T2 漂浮的鸭子

  一道强连通分量的裸题。常见的算法是Tarjan:

  1 /**
  2  * luogu.org
  3  * Problem#2049
  4  * Accepted
  5  * Time:150ms
  6  * Memory:18527k
  7  */
  8 #include<iostream>
  9 #include<fstream>
 10 #include<sstream>
 11 #include<cstdio>
 12 #include<cstdlib>
 13 #include<cstring>
 14 #include<ctime>
 15 #include<cctype>
 16 #include<cmath>
 17 #include<algorithm>
 18 #include<stack>
 19 #include<queue>
 20 #include<set>
 21 #include<map>
 22 #include<vector>
 23 using namespace std;
 24 typedef bool boolean;
 25 #define smin(a, b)    (a) = min((a), (b))
 26 #define smax(a, b)    (a) = max((a), (b))
 27 template<typename T>
 28 inline void readInteger(T& u){
 29     char x;
 30     int aFlag = 1;
 31     while(!isdigit((x = getchar())) && x != \'-\' && x != -1);
 32     if(x == -1)    return;
 33     if(x == \'-\'){
 34         x = getchar();
 35         aFlag = -1;
 36     }
 37     for(u = x - \'0\'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - \'0\');
 38     ungetc(x, stdin);
 39     u *= aFlag;
 40 }
 41 
 42 int cv = 0, cc = 0;
 43 stack<int> s;
 44 int* visitID;
 45 int* exitID;
 46 boolean* instack;
 47 boolean* visited;
 48 int* belong;
 49 int* next;
 50 
 51 void getSonMap(int end){
 52     int d;
 53     cc++;
 54     do{
 55         d = s.top();
 56         s.pop();
 57         belong[d] = cc;
 58         instack[d] = false;
 59     }while(d != end);
 60 }
 61 
 62 void Tarjan(int node){
 63     visitID[node] = exitID[node] = ++cv;
 64     visited[node] = true;
 65     s.push(node);
 66     instack[node] = true;
 67     if(!visited[next[node]]){
 68         Tarjan(next[node]);
 69         smin(exitID[node], exitID[next[node]]);
 70     }else if(instack[next[node]]){
 71         smin(exitID[node], visitID[next[node]]);
 72     }
 73     if(exitID[node] == visitID[node])
 74         getSonMap(node);
 75 }
 76 
 77 int n;
 78 int *len;
 79 int *clen;
 80 
 81 inline void init(){
 82     readInteger(n);
 83     visitID = new int[(const int)(n + 1)];
 84     exitID = new int[(const int)(n + 1)];
 85     instack = new boolean[(const int)(n + 1)];
 86     visited = new boolean[(const int)(n + 1)];
 87     belong = new int[(const int)(n + 1)];
 88     next = new int[(const int)(n + 1)];
 89     len = new int[(const int)(n + 1)];
 90     memset(visited, false, sizeof(boolean) * (n + 1));
 91     memset(instack, false, sizeof(boolean) * (n + 1));
 92     for(int i = 1; i <= n; i++){
 93         readInteger(next[i]);
 94         readInteger(len[i]);
 95     }
 96 }
 97 
 98 int result = 0;
 99 boolean* vis;
100 
101 inline void solve(){
102     for(int i = 1; i <= n; i++)
103         if(!visited[i])
104             Tarjan(i);
105     delete[] visitID;
106     delete[] visited;
107     delete[] instack;
108     delete[] exitID;
109     clen = new int[(const int)(cc + 1)];
110     vis = new boolean[(const int)(cc + 1)];
111     memset(vis, false, sizeof(boolean) * (cc + 1)); 
112     for(int i = 1; i <= n; i++){
113         if(!vis[belong[i]]){
114             int j = i;
115             int l = 0;
116             while(belong[next[j]] == belong[i] && next[j] != i){
117                 l += len[j];
118                 j = next[j];
119             }
120             l += len[j];
121             vis[belong[i]] = true;
122             smax(result, l);
123         }
124     }
125     printf("%d", result);
126 }
127 
128 int main(){
129     init();
130     solve();
131     return 0;
132 }

  仔细读题,每个点的出度为1,那么实际上dfs就好了,用不着Tarjan,还开辣么多数组。

 1 /**
 2  * luogu.org
 3  * Problem#2049
 4  * Accepted
 5  * Time:107ms
 6  * Memory:17941k
 7  */
 8 #include<iostream>
 9 #include<fstream>
10 #include<sstream>
11 #include<cstdio>
12 #include<cstdlib>
13 #include<cstring>
14 #include<ctime>
15 #include<cctype>
16 #include<cmath>
17 #include<algorithm>
18 #include<stack>
19 #include<queue>
20 #include<set>
21 #include<map>
22 #include<vector>
23 using namespace std;
24 typedef bool boolean;
25 #define smin(a, b)    (a) = min((a), (b))
26 #define smax(a, b)    (a) = max((a), (b))
27 template<typename T>
28 inline void readInteger(T& u){
29     char x;
30     int aFlag = 1;
31     while(!isdigit((x = getchar())) && x != \'-\' && x != -1);
32     if(x == -1)    return;
33     if(x == \'-\'){
34         x = getchar();
35         aFlag = -1;
36     }
37     for(u = x - \'0\'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - \'0\');
38     ungetc(x, stdin);
39     u *= aFlag;
40 }
41 
42 int n;
43 int cc = 0;
44 int *belong;
45 int *next;
46 int *len;
47 int *dist;
48 int result = 0;
49 
50 void dfs(int node, int be){
51     belong[node] = be;
52     if(belong[next[node]] == be){
53         int dis = dist[node] - dist[next[node]] + len[node];
54         smax(result, dis);
55     }
56     if(belong[next[node]] == 0){
57         dist[next[node]] = dist[node] + len[node];
58         dfs(next[node], be);
59     }
60 }
61 
62 inline void init(){
63     readInteger(n);
64     belong = new int[(const int)(n + 1)];
65     next = new int[(const int)(n + 1)];
66     len = new int[(const int)(n + 1)];
67     dist = new int[(const int)(n + 1)];
68     memset(belong, 0, sizeof(int) * (n + 1));
69     for(int i = 1; i <= n; i++){
70         readInteger(next[i]);
71         readInteger(len[i]);
洛谷题解part

[NOIP2015提高&洛谷P2678]跳石头 题解(二分答案)

洛谷P1309 瑞士轮

洛谷2018寒假集训tg第二次比赛第二题Princess Principal题解

洛谷 P2678 跳石头 题解

洛谷1273:有线电视网——题解