接毒瘤

【题目描述】
24OI的成员跑到了一片大森林,目的是摘一些毒瘤回去给高一同学吃。
于是在毒瘤树下,cyl沿着一条线钉了N个木桩,并且在相邻两个木桩之间结网,初始时所有的网中都没有毒瘤。
之后,树上可能会掉下毒瘤,cyl也可能拿走一部分毒瘤,我们统一把它们称为“操作”。
在等毒瘤落下的cyl同学正在思考一个问题:对于给定的l,r(l<r),在第l个木桩到第r个木桩里等概率随机取出两个不同的木桩a和b,那么从min(a,b)到max(a,b)之间的所有的网中的毒瘤总数期望有多少呢?


【输入输出格式】
输入格式:
第一行2个正整数N,M,表示有N个木桩,M个操作或询问。
接下来M行,每行将出现以下两种形式中的一种:
C l r v
如果v>=0,表示第l个木桩到第r个木桩之间的每个网中都接到了v个毒瘤;
否则表示cyl从第l个木桩到第r个木桩之间的每个网中都拿走了v个毒瘤;
Q l r
表示对于给定的l,r,要求回答cyl的问题;
所有操作或询问中保证1<=l<r<=N


输出格式:
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1


【输入样例】
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4


【输出样例】
1/1
8/3
17/6


【说明】

所有C操作中的v的绝对值不超过10000。
在任何时刻任意网内的毒瘤个数均为不超过10000的非负整数。


所有测试点的详细情况如下表所示:
Test N M
1 =10 =10
2 =20 =20
3 =100 =100
4 =300 =300
5 =350 =350
6 =2000 =2000
7 =5000 =5000
8 =10000 =10000
9 =50000 =50000
10 =100000 =100000

 

首先得知道期望是什么:就是该区间内 a, b 的每一种情况所对应的毒瘤数之和除以情况数目。

 

对了,题中说是两个木桩之间一个网兜,这么做不太方便,我们默认第i个网兜就属于这个网兜左边连着的木桩。

所以对于所有的r,都应r--。

 

接着说期望,比如区间2到5,那么总情况数就是 [2, 2], [2, 3], [2, 4], [2, 5], [3, 3], [3, 4], [3, 5], [4, 4], [4, 5], [5, 5]。

那么对于长度为 L (L = r - l + 1)的区间,总情况数就是1 + 2 + 3 + 4 + …… + L。

因此只要预处理一个前缀和数组就能解决分母了。

 

接下来是分子,即每一个情况所对应的毒瘤数之和。

我们可以换一种思路,去求网兜i在 l 到r区间里总共出现了多少次。

于是易得

    次数 = (i - l + 1) * (r  - i + 1) * w[i]  (1)

w[i]为当前网兜 i 里的毒瘤数

于是

    总次数 = sum((i - l +1) * (r - i + 1) * w[i])  (i : l -> r)

对于(1), 当我们把括号打开后

  次数 = - i * i * w[i] + (r + l) * i * w[i] + (-l * r - l + r + 1) * w[i]

于是线段树就派上用场了,开一个线段树,同时维护sum1(w[i]), sum2(i * w[i]), sum3(i * i * w[i]).

 

对于sum1(w[i]),就是普通的区间求和。

对于sum2(i * w[i]),若是区间每一个数加 v,则这个区间的sum2就增加了(l + (l + 1) + (l + 2) + …… + r)。于是我们可以预处理一个前缀和(其实和分母的前缀和一样)。

对于sum3(i * i * w[i]),若是区间每一个数加v,则这个区间sum3就增加了(l ^ 2 + (l + 1) ^ 2 + (l + 2) ^ 2 +…… + r ^ 2)。于是同样可以预处理一个i ^ 2的前缀和。

综上,一个lazy[],三个sum[].

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long ll;
  8 const int maxn = 2e5 + 5;
  9 
 10 int n, m;
 11 ll sigma1[maxn], sigma2[maxn];
 12 ll ans1 = 0, ans2 = 0, ans3 = 0;
 13 
 14 void init(int n)
 15 {
 16     for(ll i = 1; i <= n; ++i)
 17     {
 18         sigma1[i] = sigma1[i - 1] + i;
 19         sigma2[i] = sigma2[i - 1] + i * i;
 20     }
 21 }
 22 
 23 struct Tree
 24 {
 25     int l, r;
 26     ll sum1, sum2, sum3;        //w[i], i * w[i],i * i * w[i]
 27     int lazy;
 28 }tree[maxn << 2];        
 29 void build(int L, int R, int now)
 30 {
 31     tree[now].l = L; tree[now].r = R;
 32     if(L == R) return;
 33     int mid = (L + R) >> 1;
 34     build(L, mid, now << 1);
 35     build(mid + 1, R, now << 1 | 1);
 36 }
 37 void update(int L, int R, int now, int v)
 38 {
 39     if(tree[now].l == L && tree[now].r == R)
 40     {
 41         tree[now].lazy += v; 
 42         return;
 43     }
 44     tree[now].sum1 += (ll) v * (R - L + 1);
 45     tree[now].sum2 += (ll) v * (sigma1[R] - sigma1[L - 1]);
 46     tree[now].sum3 += (ll) v * (sigma2[R] - sigma2[L - 1]);
 47     int mid = (tree[now].l + tree[now].r) >> 1;
 48     if(R <= mid) update(L, R, now << 1, v);
 49     else if(L > mid) update(L, R, now << 1 | 1, v);
 50     else {update(L, mid, now << 1, v); update(mid + 1, R, now << 1 | 1, v);}
 51 }
 52 void pushdown(int now)
 53 {
 54     if(tree[now].lazy)
 55     {
 56         tree[now].sum1 += (ll) tree[now].lazy * (tree[now].r - tree[now].l + 1);
 57         tree[now].sum2 += (ll) tree[now].lazy * (sigma1[tree[now].r] - sigma1[tree[now].l - 1]);
 58         tree[now].sum3 += (ll) tree[now].lazy * (sigma2[tree[now].r] - sigma2[tree[now].l - 1]);
 59         tree[now << 1].lazy += tree[now].lazy;
 60         tree[now << 1 | 1].lazy += tree[now].lazy;
 61         tree[now].lazy = 0;
 62     }
 63 }
 64 void query(int L, int R, int now)
 65 {
 66     pushdown(now);
 67     if(tree[now].l == L && tree[now].r == R)
 68     {
 69         ans1 += tree[now].sum1;
 70         ans2 += tree[now].sum2;
 71         ans3 += tree[now].sum3;
 72         return;
 73     }
 74     int mid = (tree[now].l + tree[now].r) >> 1;
 75     if(R <= mid) query(L, R, now << 1);
 76     else if(L > mid) query(L, R, now << 1 | 1);
 77     else {query(L, mid, now << 1); query(mid + 1, R, now << 1 | 1);}
 78 }
 79 ll gcd(ll x,ll y) 
 80 {
 81     return y ? gcd(y, x % y) : x;
 82 }
 83 
 84 int main()
 85 {
 86     scanf("%d%d", &n, &m); 
 87     init(n);
 88     build(1, n, 1);
 89     for(int i = 1; i <= m; ++i)
 90     {
 91         char c; int L, R;
 92         cin >> c; scanf("%d%d", &L, &R);
 93         R--;
 94         if(c == 'C')
 95         {
 96             int v; scanf("%d", &v);
 97             update(L, R, 1, v);
 98         }
 99         else
100         {
101             ans1 = ans2 = ans3 = 0;
102             query(L, R, 1);
103             ll Upans = (R - L - (ll)L * R + 1) * ans1 + (R + L) * ans2 - ans3;
104             ll Downans = sigma1[R - L + 1];
105             ll div = gcd(Upans, Downans);
106             printf("%lld/%lld\n", Upans / div, Downans / div);
107         }
108     }
109     return 0;
110 }

 

上一篇:Python for Data Science - Delving into non-parametric methods using pandas and scipy


下一篇:bootstrap插件思路整理