2026-05-28~06-02 hetao1733837 的刷题记录

2026-05-28~06-02 hetao1733837 的刷题记录

05-28

我将开始大战数学相关!

LGP12122 蓝桥杯 2024 省 B 第二场 逆序对期望

原题链接:蓝桥杯 2024 省 B 第二场 逆序对期望

分析

这是橙?对于第一次交换,是好做的,第二次要分讨。

那么,如果我们第一次交换了 i , j i,j i,j,不妨 i < j i<j i<j,那么,第二次交换 k , l k,l k,l,同样不妨 k , l k,l k,l,则有:


  • i < j , k < l , i , j k , l = ∅ i<j,k<l,i,j\cap k,l=\varnothing i<j,k<l,i,jk,l=∅,则答案为 2 51 × ( 2 i − 1 + 2 n − j ) × ( j − i − 1 ) + ( l − k − 1 ) \frac{2}{51}\times(\frac{2}{i-1}+\frac{2}{n-j})\times(j - i - 1)+(l-k-1) 512×(i−12+n−j2)×(j−i−1)+(l−k−1),对吗?

有点阴间了,这个东西直接结论就是: E ( x ) = 4 ( n − 2 ) 3 E(x)=\frac{4(n-2)}{3} E(x)=34(n−2),但是,为什么?布吉岛。不过似乎有一个 O ( n 5 l o g n ) O(n^5logn) O(n5logn) 的暴力,不过我已经几亿年不回归并排序了/ll

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
signed main(){
    cout << "65.33";
}

LGP9217 「TAOI-1」拼凑的断音

原题链接:「TAOI-1」拼凑的断音

分析

好的,似乎有什么思路了......就是对于那些怎么加都超不过原始序列最大值的,抛弃掉。剩下的,最大值是好做的,因为可以有类似于等比数列的东西。

换个视角的问题,我们把序列最大值加 s s s 钦定,那么, p × ( m x + s ) q \frac{p\times (mx+s)}{q} qp×(mx+s) 呃,还有一坨概率没算......然后,剩下的,钦定最大值加 s s s 不选,即 1 − p q 1-\frac{p}{q} 1−qp,然后再去弄。好阴啊。

瞅一眼题解看看概率是怎么做的,肯定是一种类似我们之前说的等比的东西。


哦,我们选了这个数之后,剩下的会自动啊吧啊吧,然后就可以了......

所以,我们得到一个式子,我们按照之前那个预处理之后降序排序,可得:

∑ i = 1 m ( 1 − p q ) ( i − 1 ) × p q × ( a i + s ) \sum\limits_{i=1}^{m}{(1-\frac{p}{q})^{(i-1)}\times\frac{p}{q}\times(a_i+s)} i=1∑m(1−qp)(i−1)×qp×(ai+s)

好像是这个东西吧......

哦,还有原始最大值,这个,把就是所有都不变的 ( 1 − p q ) n (1-\frac{p}{q})^n (1−qp)n 的概率去乘即可。看看哪种取模比较优雅吧,这么一推,似乎第二种是优雅的。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 100005;
int n, p, q, s, a[N];
int qpow(int a, int b){
	int res = 1;
	while (b){
		if (b & 1){
			res = res * a % mod;
		}
		b >>= 1;
		a = a * a % mod;
	}
	return res;
} 
int mx;
vector<int> num;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> p >> q >> s;
	for (int i = 1; i <= n; i++){
		cin >> a[i];
		mx = max(mx, a[i]);
	}
	for (int i = 1; i <= n; i++){
		if (a[i] + s > mx){
			num.push_back(a[i]);
		}
	}
	sort(num.begin(), num.end(), greater<int>());
	int ans = 0;
	for (int i = 0; i < (int)num.size(); i++){
		int j = i + 1;
		ans = (ans + qpow((q - p) * qpow(q, mod - 2) % mod, j - 1) % mod * p % mod * qpow(q, mod - 2) % mod * (num[i] + s) % mod) % mod;
	}
	ans = (ans + mx * qpow((q - p) * qpow(q, mod - 2) % mod, (int)num.size())) % mod;
	cout << 2 << '\n';
    cout << ans;
}

LGP11046 蓝桥杯 2024 省 Java B 星际旅行

原题链接:蓝桥杯 2024 省 Java B 星际旅行

分析

显然有一个图在里面......哦,看来就是 bfs 了。那么,启动!差点以为是图上随机游走了。

好吧,纯写 bfs 是全 MLE 的,不知道为啥,可能是我太菜了/ll

那么,不妨跑一遍 Dijkstra,对于那些 d i s x i , j ≤ y i dis_{x_i,j}\le y_i disxi,j≤yi 的,加一下,最后出答案统一除以 Q Q Q。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, m, Q;
vector<int> e[N];
int d[N][N];
bool vis[N];
void dijkstra(int S){
    memset(vis, 0, sizeof(vis));
    d[S][S] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    q.push({0, S});
    while (!q.empty()){
        int u = q.top().second;
        q.pop();
        if (vis[u]) 
            continue;
        vis[u] = true;
        for (int v : e[u]){
            if (d[S][v] > d[S][u] + 1){
                d[S][v] = d[S][u] + 1;
                q.push({d[S][v], v});
            }
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); 
    cout.tie(0);
    cin >> n >> m >> Q;
    for (int i = 1, a, b; i <= m; i++){
        cin >> a >> b;
        e[a].push_back(b);
        e[b].push_back(a);
    }
    memset(d, 0x3f, sizeof(d));
    for (int i = 1; i <= n; i++){
        dijkstra(i);
    }
    long long ans = 0;
    for (int i = 1, x, y; i <= Q; i++){
        cin >> x >> y;
        for (int j = 1; j <= n; j++){
            if (d[x][j] <= y) 
                ans++;
        }
    }
    cout << fixed << setprecision(2) << (double)ans / Q;
    return 0;
}

启动 BO

05-30

LGP13800 SWERC 2023 Throwing dice

原题链接:SWERC 2023 Throwing dice

分析

看蒙了,吓哭了/ll

我不会/ll

无法直输骗分/ll

好吧,猜到了,但是不是很会证。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, m, a[N], b[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> m >> n;
    int suma = 0, sumb = 0;
    for (int i = 1; i <= m; i++){
        cin >> a[i];
        suma += a[i];
    }
    for (int i = 1; i <= n; i++){
        cin >> b[i];
        sumb += b[i];
    }
    if (suma + m > sumb + n){
        cout << "ALICE";
    }
    else if (suma + m == sumb + n){
        cout << "TIED";
    }
    else{
        cout << "BOB";
    }
}

05-31

LGP4550 收集邮票

原题链接:收集邮票

分析

我为何看不出怎么算的?看题解。


期望 DP ,❓

我们设 f i f_i fi 表示取到了第 i i i 张,取完剩下的期望次数,则有转移:

f i = i n × f i + n − i n × f i + 1 + 1 f_i=\frac{i}{n}\times f_i+\frac{n-i}{n}\times f_{i+1}+1 fi=ni×fi+nn−i×fi+1+1

设 g i g_i gi 表示取到第 i i i 张,取完剩下的期望价格,则有转移:

g i = i n × ( g i + f i + 1 ) + n − i n × ( g i + 1 + f i + 1 + 1 ) g_i=\frac{i}{n}\times (g_i+f_i+1)+\frac{n-i}{n}\times (g_{i+1}+f_{i+1}+1) gi=ni×(gi+fi+1)+nn−i×(gi+1+fi+1+1)

其中, f n = g n = 0 f_n=g_n=0 fn=gn=0。

不化简影响这么大吗?

行吧,那么化简可得:

f i = f i + 1 + n n − i g i = i n − i × f i + g i + 1 + f i + 1 + n n − i f_i=f_{i+1}+\frac{n}{n-i} \\ g_i=\frac{i}{n-i}\times f_i+g_{i+1}+f_{i+1}+\frac{n}{n-i} fi=fi+1+n−ingi=n−ii×fi+gi+1+fi+1+n−in

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int n;
double f[N], g[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = n - 1; i >= 0; i--){
        f[i] = f[i + 1] + 1.0 * n / (n - i);
        g[i] = 1.0 * i / (n - i) * (f[i] + 1) + g[i + 1] + f[i + 1] + 1;
    }
    cout << fixed << setprecision(2) << g[0];
    return 0;
}

CF148D Bag of mice

原题链接:D. Bag of mice

分析

好的,作为第一道概率 DP 题。

设 d p i , j dp_{i,j} dpi,j 表示袋子里有 i i i 只白鼠, j j j 只黑鼠时,公主获胜的概率。

那么,对于所有 d p i , 0 dp_{i,0} dpi,0,公主必胜。对于所有 d p 0 , j dp_{0,j} dp0,j,龙必胜。即 d p i , 0 = 1 , d p 0 , j = 0 dp_{i,0}=1,dp_{0,j}=0 dpi,0=1,dp0,j=0。

那么有转移:

d p i , j + = { i i + j j i + j × j − 1 i + j − 1 × j − 2 i + j − 2 × d p i , j − 3 ( j ≥ 3 ) j i + j × j − 1 i + j − 1 × i i + j − 2 × d p i − 1 , j − 2 ( i ≥ 1 , j ≥ 2 ) dp_{i,j}+= \begin{cases} \frac{i}{i+j}\\ \frac{j}{i+j}\times\frac{j-1}{i+j-1}\times\frac{j-2}{i+j-2}\times dp_{i, j-3} (j\ge 3)\\ \frac{j}{i+j}\times\frac{j-1}{i+j-1}\times\frac{i}{i+j-2}\times dp_{i-1, j-2} (i\ge 1,j\ge 2) \end{cases} dpi,j+=⎩ ⎨ ⎧i+jii+jj×i+j−1j−1×i+j−2j−2×dpi,j−3(j≥3)i+jj×i+j−1j−1×i+j−2i×dpi−1,j−2(i≥1,j≥2)

分别表示:公主直接抓了一只白鼠;公主,龙分别抓一只黑鼠,跑出来一只黑鼠;公主,龙分别抓一只黑鼠,跑出来一只白鼠的概率。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int w, b;
double dp[N][N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> w >> b;
    for (int i = 1; i <= w; i++){
        dp[i][0] = 1;
    }
    for (int j = 1; j <= b; j++){
        dp[0][j] = 0;
    }
    for (int i = 1; i <= w; i++){
        for (int j = 1; j <= b; j++){
            dp[i][j] += (0.0 + i) / (0.0 + i + j);
            if (j >= 3){
                dp[i][j] += (0.0 + j) / (0.0 + i + j) * (0.0 + j - 1) / (0.0 + i + j - 1) * (0.0 + j - 2) / (0.0 + i + j - 2) * dp[i][j - 3];
            }
            if (i >= 1 && j >= 2){
                dp[i][j] += (0.0 + j) / (0.0 + i + j) * (0.0 + j - 1) / (0.0 + i + j - 1) * (0.0 + i) / (0.0 + i + j - 2) * dp[i - 1][j - 2];
            }
        }
    }
    cout << fixed << setprecision(9) << dp[w][b];
}

CF768D Jon and Orbs

原题链接:D. Jon and Orbs

分析

愣了几秒,发现自己好像没有看懂题面。

好吧,看了题解,把题面看懂了:

K K K 种物品,求一次取一件把所有种类取遍的概率不小于 p i 2000 \frac{p_i}{2000} 2000pi 的最小天数。 p i p_i pi 有 Q Q Q 次询问。


那么,对于 K − K ≥ p i 2000 K^{-K}\ge \frac{p_i}{2000} K−K≥2000pi,直接输出似乎就可以了。

正常的话,难道设 d p i , j dp_{i,j} dpi,j 表示进行了 i i i 天,抽出 j j j 种的概率?那么,转移应该形如:

d p i + 1 , j = d p i , j × 1 C j 1 d p i + 1 , j + 1 = d p i , j × 1 C n − j 1 dp_{i+1,j}=dp_{i,j}\times\frac{1}{C_{j}^{1}}\\ dp_{i+1,j+1}=dp_{i,j}\times\frac{1}{C_{n-j}^{1}} dpi+1,j=dpi,j×Cj11dpi+1,j+1=dpi,j×Cn−j11

果真如此吗?那么, d p i , 0 = 0 , d p 0 , j = 0 , d p 0 , 0 = 1 , d p i , i = K − i dp_{i,0}=0,dp_{0,j}=0,dp_{0,0}=1,dp_{i,i}=K^{-i} dpi,0=0,dp0,j=0,dp0,0=1,dpi,i=K−i?

那我怎么搞边界?算了,看看题解吧。


哦,转移思路错了,DP,不只是概率DP,都要从之前有的转移,从之前没有的转移,那叫递归,那不是记忆化搜索!

所以,真正的转移形如:

d p i , j + = { d p i − 1 , j × j k d p i − 1 , j − 1 × k − j + 1 k dp_{i,j}+= \begin{cases} dp_{i-1,j}\times\frac{j}{k}\\ dp_{i-1,j-1}\times\frac{k-j+1}{k} \end{cases} dpi,j+={dpi−1,j×kjdpi−1,j−1×kk−j+1

对于天数,一种方法是可以根据复杂度直接开到最大,另一种自己推导(题解提到了约 7500 7500 7500 天),我们直接开到 1 × 10 4 1\times10^4 1×104。

初始化也没有那么麻烦,只需要: d p 0 , 0 = 1 dp_{0,0}=1 dp0,0=1 即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int M = 10005, K = 1005;
int k, q, p[M];
double dp[M][K];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> k >> q;
    for (int i = 1; i <= q; i++){
        cin >> p[i];
    }
    dp[0][0] = 1;
    for (int i = 1; i <= 10000; i++){
        for (int j = 1; j <= k; j++){
            dp[i][j] = dp[i - 1][j] * (double)j / k + dp[i - 1][j - 1] * (double)(k - j + 1) / k;
        }
    }
    for (int i = 1; i <= q; i++){
        int ans = 1;
        for (int j = 1; j <= 10000; j++){
            if (dp[j][k] < p[i] / 2000.0){
                ans++;
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

哦,原来第一发把两个维度搞反了吗/jk

06-01

lz 的恩情还不完,居然给我们蜜雪冰城/ll

好吧,我回家给 zjx 转💴

LGP1850 NOIP 2016 提高组 换教室

原题链接:NOIP 2016 提高组 换教室

分析

居然已经 10 年了吗?好吧,我的人生已经可以以 10 年这个单位来计算了。

我到底在伤感什么?

首先,我要跑一个 O ( v 3 ) O(v^3) O(v3) 的全源最短路,非常好啊!

然后,我们设 f i , j , 0 / 1 f_{i,j,0/1} fi,j,0/1 表示对于第 i i i 节课,已经申请了 j j j 次,这节课申请/不申请的概率(怎么有点怪怪的?)。

转移有:

f i , j , 0 = f i − 1 , j , 0 f i , j , 1 = f i − 1 , j − 1 , 0 × 1 k i + f i − 1 , j − 1 , 1 × 1 k i f_{i,j,0}=f_{i-1,j,0}\\ f_{i,j,1}=f_{i-1,j-1,0}\times \frac{1}{k_i}+f_{i-1,j-1,1}\times \frac{1}{k_i} fi,j,0=fi−1,j,0fi,j,1=fi−1,j−1,0×ki1+fi−1,j−1,1×ki1

感觉这个好假啊......

设 g i , j , 0 / 1 g_{i,j,0/1} gi,j,0/1 表示对于第 i i i 节课,已经申请了 j j j 次,这节课申请/不申请的期望(怎么也有点怪怪的?)。

转移有:

g i , j , 0 = g i − 1 , j , 0 × d c i − 1 , c i g i , j , 0 = g i − 1 , j − 1 , 0 × d c i − 1 , d i + g i − 1 , j − 1 , 1 × d c i − 1 , d i g_{i,j,0}=g_{i-1,j,0}\times d_{c_{i-1}, c_i}\\ g_{i,j,0}=g_{i-1,j-1,0}\times d_{c_{i-1}, d_i}+g_{i-1,j-1,1}\times d_{c_{i-1}, d_i} gi,j,0=gi−1,j,0×dci−1,cigi,j,0=gi−1,j−1,0×dci−1,di+gi−1,j−1,1×dci−1,di

答案为 min ⁡ i = 1 m min ⁡ { g n , i , 0 / 1 } \min\limits_{i=1}^{m}{\min\{g_{n,i,0/1}\}} i=1minmmin{gn,i,0/1}。

这个转移感觉假完了/ll


不算完全失败吧。首先,那个 Floyd 想到了。然后,那个状态其实也算是比较接近了,不过差点火候。

我们设 d p i , j , 0 / 1 dp_{i,j,0/1} dpi,j,0/1 表示考虑了前 i i i 个教室,换了 j j j 次,第 i i i 个教室申请换/不申请换的最小期望值。

那么,转移显然:

d p i , j , 0 = min ⁡ ( d p i − 1 , j , 0 + d i s c i − 1 , c i , d p i − 1 , j − 1 , 1 + d i s c i − 1 , c i × ( 1 − k i − 1 ) + d i s d i − 1 , c i × k i − 1 ) d p i , j , 1 = min ⁡ ( d p i − 1 , j − 1 , 0 + d i s c i − 1 , c i × ( 1 − k i − 1 ) + d i s c i − 1 , d i × k i , d p i − 1 , j − 1 , 1 + d i s d i − 1 , d i × k i × k i − 1 + d i s d i − 1 , c i × k i − 1 × ( 1 − k i ) + d i s d i − 1 , d i × ( 1 − k i − 1 ) × k i + d i s c i − 1 , c i × ( 1 − k i − 1 ) × ( 1 − k i ) ) dp_{i,j,0}=\min(dp_{i-1,j,0}+dis_{c_{i-1},c_i},dp_{i-1,j-1,1}+ dis_{c_{i-1},c_i}\times(1-k_{i-1})+dis_{d_{i-1},c_i}\times k_{i-1})\\ dp_{i,j,1}=\min(dp_{i-1,j-1,0}+dis_{c_{i-1},c_i}\times(1-k_{i-1})+dis_{c_{i-1},d_i}\times k_i,dp_{i-1,j-1,1}+dis_{d_{i-1},d_i}\times k_i\times k_{i-1}+dis_{d_{i-1},c_i}\times k_{i-1}\times(1-k_i)+dis_{d_{i-1},d_i}\times(1-k_{i-1})\times k_i+dis_{c_{i-1},c_{i}}\times(1-k_{i-1})\times(1-k_i)) dpi,j,0=min(dpi−1,j,0+disci−1,ci,dpi−1,j−1,1+disci−1,ci×(1−ki−1)+disdi−1,ci×ki−1)dpi,j,1=min(dpi−1,j−1,0+disci−1,ci×(1−ki−1)+disci−1,di×ki,dpi−1,j−1,1+disdi−1,di×ki×ki−1+disdi−1,ci×ki−1×(1−ki)+disdi−1,di×(1−ki−1)×ki+disci−1,ci×(1−ki−1)×(1−ki))

简直了/tuu

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2005, V = 305;
const double INF = 1e18;
int n, m, v, cnte;
int c[N], d[N];
double k[N];
double dp[N][N][2];
int dis[V][V];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m >> v >> cnte;
    for (int i = 1; i <= n; i++) 
        cin >> c[i];
    for (int i = 1; i <= n; i++) 
        cin >> d[i];
    for (int i = 1; i <= n; i++) 
        cin >> k[i];
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 1; i <= v; i++) 
        dis[i][i] = 0; 
    for (int i = 1, a, b, w; i <= cnte; i++){
        cin >> a >> b >> w;
        dis[a][b] = dis[b][a] = min({dis[a][b], dis[b][a], w});
    }
    for (int k = 1; k <= v; k++)
        for (int i = 1; i <= v; i++)
            for (int j = 1; j <= v; j++)
                if (dis[i][k] != 0x3f3f3f3f && dis[k][j] != 0x3f3f3f3f)
                    dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= m; j++)
            dp[i][j][0] = dp[i][j][1] = INF;
    dp[1][0][0] = 0;
    if (m >= 1) 
        dp[1][1][1] = 0;
    for (int i = 2; i <= n; i++){
        dp[i][0][0] = dp[i - 1][0][0] + dis[c[i - 1]][c[i]];
        for (int j = 1; j <= min(i, m); j++){
            dp[i][j][0] = min(dp[i - 1][j][0] + dis[c[i - 1]][c[i]],
                              dp[i - 1][j][1] + dis[c[i - 1]][c[i]] * (1 - k[i - 1]) + dis[d[i - 1]][c[i]] * k[i - 1]);
            dp[i][j][1] = min(dp[i - 1][j - 1][0] + dis[c[i - 1]][c[i]] * (1 - k[i]) + dis[c[i - 1]][d[i]] * k[i],
                              dp[i - 1][j - 1][1] + dis[d[i - 1]][d[i]] * k[i - 1] * k[i] + dis[d[i - 1]][c[i]] * k[i - 1] * (1 - k[i]) + dis[c[i - 1]][d[i]] * (1 - k[i - 1]) * k[i] + dis[c[i - 1]][c[i]] * (1 - k[i - 1]) * (1 - k[i]));
        }
    }
    double ans = INF;
    for (int i = 0; i <= m; i++)
        ans = min({ans, dp[n][i][0], dp[n][i][1]});
    cout << fixed << setprecision(2) << ans;
    return 0;
}

AT-arc219-b ARC219B Reverse Permutation

原题链接:B - Reverse Permutation

分析

他管这个玩意叫黄?

放了 O ( n l o g n ) O(nlogn) O(nlogn),思考一下......

难道说对于每个位置进行思考?bur,这么狠吗?上来就给我整个这?

对,第一次看题想到了 字典序只考虑第一位和最后一位,好吧,我承认,最后一位我没想全。


哦,题解的意思应该是,就是对于每一个数 i i i,都有 n − i n-i n−i 个数比他大,换了字典序就变小,所以加一下,最后就能构造出来?然后由于这个要是不相同的话,那么后面的字典序应该就乱了,需要跳出来。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
const int N = 500005;
int T;
int n, p[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    for (int cs = 1; cs <= T; cs++){
        int ans = 1;
        cin >> n;
        for (int i = 1; i <= n; i++){
            cin >> p[i];
        }
        for (int i = 1; i <= n; i++){
            if (p[i] == i){
                ans = (ans + n - i) % mod;
            }
            else{
                ans = (ans - 1 + mod) % mod;
                break;
            }
        }
        cout << ans << '\n';
    }
}

06-02

LGP2221 HAOI2012 高速公路

原题链接:HAOI2012 高速公路

分析

区间加+区间求和,显然是线段树。剩下的,我来尝试一个式子。哦,需要线段树维护一下 i × a i i\times a_i i×ai,做完了。

要不直接开贺吧......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, m;
char op;
int l, r, v;
int sum1, sum2, sum3;
struct segtree{
    struct node{
        int sum[10], tag, l, r;
    }tr[N << 2];
    void pushup(int p){
        tr[p].sum[1] = tr[p << 1].sum[1] + tr[p << 1 | 1].sum[1];
        tr[p].sum[2] = tr[p << 1].sum[2] + tr[p << 1 | 1].sum[2];
        tr[p].sum[3] = tr[p << 1].sum[3] + tr[p << 1 | 1].sum[3];
    }
    void build(int p, int l, int r){
        tr[p].l = l;
        tr[p].r = r;
        if (l == r){
            tr[p].sum[4] = l * l;
            tr[p].sum[5] = l;
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        tr[p].sum[4] = tr[p << 1].sum[4] + tr[p << 1 | 1].sum[4];
        tr[p].sum[5] = tr[p << 1].sum[5] + tr[p << 1 | 1].sum[5];
    }
    void calc(int p, int k){
        tr[p].sum[1] += (tr[p].r - tr[p].l + 1) * k;
        tr[p].sum[2] += tr[p].sum[5] * k;
        tr[p].sum[3] += tr[p].sum[4] * k;
        tr[p].tag += k;
    }
    void down(int p){
        calc(p << 1, tr[p].tag);
        calc(p << 1 | 1, tr[p].tag);
        tr[p].tag = 0;
    }
    void modify(int p, int s, int t, int val){
        if (s <= tr[p].l && tr[p].r <= t){
            calc(p, val);
            return ;
        }
        if (tr[p].tag) 
            down(p);
        int mid = (tr[p].l + tr[p].r) >> 1;
        if (s <= mid) 
            modify(p << 1, s, t, val); 
        if (t > mid)  
            modify(p << 1 | 1, s, t, val); 
        pushup(p);
    }
    void query(int p, int s, int t){
        if (s <= tr[p].l && tr[p].r <= t){
            sum1 += tr[p].sum[1];
            sum2 += tr[p].sum[2];
            sum3 += tr[p].sum[3];
            return ;
        }
        if (tr[p].tag) 
            down(p);
        int mid = (tr[p].l + tr[p].r) >> 1;
        if (s <= mid) 
            query(p << 1, s, t);
        if (t > mid)  
            query(p << 1 | 1, s, t);
    }
}T;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    T.build(1, 1, n);
    for (int cs = 1; cs <= m; cs++){
        cin >> op;
        if (op == 'C'){
            cin >> l >> r >> v;
            r--; 
            T.modify(1, l, r, v);
        } 
        else{
            cin >> l >> r;
            r--;
            sum1 = sum2 = sum3 = 0;
            T.query(1, l, r);
            int tmp1 = (r - l + 1 - r * l) * sum1 + (l + r) * sum2 - sum3;
            int tmp2 = (r - l + 2) * (r - l + 1) / 2;
            int GCD = __gcd(tmp1, tmp2);
            cout << tmp1 / GCD << "/" << tmp2 / GCD << '\n';
        }
    }
    return 0;
}

原来这样就可以吗/xia

相关推荐
ZhengEnCi1 小时前
O08-单写线程与单读线程冲突分析
算法
wunaiqiezixin1 小时前
如何在C++中实现一个单例模式?
c++·单例模式
仍然.1 小时前
算法题目---优先级队列
算法
一个爱编程的人1 小时前
图的相关概念
c++·算法·图论
迈巴赫车主1 小时前
贪心算法
算法·贪心算法
星马梦缘2 小时前
死锁与进程资源分配问题的解法
算法·操作系统·深度优先·死锁
爱炼丹的James2 小时前
第四章 数学知识
算法
吃好睡好便好2 小时前
矩阵旋转的计算
学习·线性代数·算法·矩阵
basketball6162 小时前
设计模式入门:2. 工厂模式详解 C++实现
开发语言·c++·设计模式