sm2025 模拟赛22 (2025.10.17)
文章目录
- T1 编辑数组
- T2 石头
- T3 括号游戏2
T1 编辑数组
link
思路
考虑差分,对于一个合法的区间,他的差分数组最后一定全为 0 0 0 。第一种操作相当于 b x + 1 , b x + 2 − 1 b_x+1,b_{x+2}-1 bx+1,bx+2−1 ,第二种操作相当于 b x − 1 , b x + 2 + 1 b_{x}-1,b_{x+2}+1 bx−1,bx+2+1 。因为要将差分数组第一位变为 0 0 0 ,只能让 b 3 b_3 b3 加 b 1 b_1 b1 ,此时 b 1 = 0 b_1=0 b1=0 ,于是对整个差分数组从前往后修改,此时已保证前面的数为 0 0 0 ,若让第 i i i 为变为 0 0 0 ,只能对 i + 2 i+2 i+2 为修改。发现这样奇偶位分离,最后得到的两个数为 0 0 0 则这个区间合法。简化限制,即 a l − a l + 1 + a l + 2 + … a r = 0 a_l-a_{l+1}+a_{l+2}+\dots a_{r}=0 al−al+1+al+2+…ar=0 且 − a l + a l + 1 − a l + 2 + … a r = 0 -a_l+a_{l+1}-a_{l+2}+\dots a_r=0 −al+al+1−al+2+…ar=0,发现只要一条式满足另一条也会满足。这个可以类似前缀和维护,枚举右端点 r r r ,求合法的 l l l 相当于 s u m r − s u m l − 1 = 0 sum_r-sum_{l-1}=0 sumr−suml−1=0 。
T2 石头
link
思路
首先有 O ( n q ) O(nq) O(nq) 暴力,枚举每个石头为起点记录它对应的取数步骤即可。
考虑对于每个询问 Q ( p , k ) Q(p,k) Q(p,k) ,易知可行的起点距离 p p p 不超过 k k k ,且区间 [ p − k + 1 , p ] [p-k+1,p] [p−k+1,p] 或 [ p , p + k − 1 ] [p,p+k-1] [p,p+k−1] 中的数一定会被取完。由大样例得答案不会很大? 因为这两部分是独立且类似的,于是考虑区间 [ p , p + k − 1 ] [p,p+k-1] [p,p+k−1] 的性质。
k = 1 k=1 k=1 很好判断,不作讨论。
首先显然 a p < a p + k a_p \lt a_{p+k} ap<ap+k ,否则答案为 0 0 0 。找到 [ p , p + k − 1 ] [p,p+k-1] [p,p+k−1] 中最大值的下标为 x x x 。若 a x < a p + k a_x \lt a_{p+k} ax<ap+k ,那么 [ x + 1 , p + k − 1 ] [x+1,p+k-1] [x+1,p+k−1] 中的所有位置都可以为起点 , x x x 若想为起点要有 [ p , x − 1 ] [p,x-1] [p,x−1] 中存在至少一个数 > \gt > [ x + 1 , p + k − 1 ] [x+1,p+k-1] [x+1,p+k−1] 中所有数;否则 a x > a p + k a_x \gt a_{p+k} ax>ap+k ,此时起点只可能在 x x x ,当且仅当 [ p , x − 1 ] [p,x-1] [p,x−1] 中的存在一个数 > \gt > [ x + 1 , p + k − 1 ] [x+1,p+k-1] [x+1,p+k−1] 中所有数且 [ p , x − 1 ] [p,x-1] [p,x−1] 以及 [ x + 1 , p + k − 1 ] [x+1,p+k-1] [x+1,p+k−1] 中所有数都 < a p + k \lt a_{p+k} <ap+k ,这时起点可以为 x x x 。可以发现只有上述情况有贡献。
注意细节。复杂度 O ( n l o g n + q ) O(nlogn+q) O(nlogn+q) 。
反思
未知 [ p , p + k − 1 ] [p,p+k-1] [p,p+k−1] 中所有数会被取完这一点。然后不会分类讨论,一直在考虑对于某个起点 i i i 左右两边扩展的先后顺序,其实整体考虑就好。
代码
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;int n,a[maxn],lg[maxn],f[maxn][20];
void Build_st(){lg[0]=-1;for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;for(int i=1;i<=n;i++)f[i][0]=i;for(int j=1;j<=lg[n];j++)for(int i=1;i+(1<<j)-1<=n;i++)f[i][j]=(a[f[i][j-1]]>a[f[i+(1<<(j-1))][j-1]]?f[i][j-1]:f[i+(1<<(j-1))][j-1]);
}int Get_st(int x,int y){if(x>y) return n+2;int k=lg[y-x+1];return a[f[x][k]]>a[f[y-(1<<k)+1][k]]?f[x][k]:f[y-(1<<k)+1][k];
}int main(){freopen("rock.in","r",stdin);freopen("rock.out","w",stdout);int id,q; scanf("%d%d%d",&id,&n,&q);for(int i=1;i<=n;i++)scanf("%d",&a[i]);Build_st();a[0]=a[n+1]=n+1,a[n+2]=0;while(q--){int p,k; scanf("%d%d",&p,&k);if(k==1){printf("1\n");continue;}int ans=0;if(p+k-1<=n){if(a[p+k]>a[p]){int x=Get_st(p,p+k-1); if(a[x]<a[p+k]){ans+=p+k-1-(x+1)+1;if(a[Get_st(p,x-1)]>a[Get_st(x+1,p+k-1)]) ans++;}else if(a[Get_st(p,x-1)]>a[Get_st(x+1,p+k-1)]&&a[Get_st(p,x-1)]<a[p+k]) ans++;}}if(p-k+1>=1){if(a[p-k]>a[p]){int x=Get_st(p-k+1,p);if(a[x]<a[p-k]){ans+=x-1-(p-k+1)+1;if(a[Get_st(p-k+1,x-1)]<a[Get_st(x+1,p)]) ans++;}else if(a[Get_st(x+1,p)]>a[Get_st(p-k+1,x-1)]&&a[Get_st(x+1,p)]<a[p-k]) ans++;}}printf("%d\n",ans);}return 0;
}
T3 括号游戏2
link
思路
概率想到转化为方案数。即 概率 = 可行方案数 总方案数 概率=\frac{可行方案数}{总方案数} 概率=总方案数可行方案数 ,总方案数为 1 × 3 × 5 × ⋯ × 2 ( n − 1 ) 1 \times 3 \times 5 \times \dots \times 2(n-1) 1×3×5×⋯×2(n−1) 。
考虑如何计算合法方案数。首先如果一轮放的不合法那么接下来就不可能合法。根据括号序列,有一个经典转换是记 (
为 + 1 +1 +1 ,)
为 − 1 -1 −1 ,那么括号序列合法相当于这个序列的前缀和的每一位都非负。
因为加一对 ()
相当于在前缀和的某一个数 x x x 后插入 x + 1 , x x+1,x x+1,x ,加入一对 )(
相当于在前缀和某一个数 x x x 后插入 x − 1 , x x-1,x x−1,x 。相当于在一个集合 S S S 中插入两个数。
考虑插入的过程,可以看成一棵有根树,将 S S S 中每一个数看做一个点。具体地,在 S S S 中插入 x , x + 1 x,x+1 x,x+1 时,找到一个点 u u u 使得 u u u 的权值为 x x x,新建两个点 v 1 , v 2 v1,v2 v1,v2 ,权值分别为 x , x + 1 x,x+1 x,x+1 ,令 u u u 为 v 1 , v 2 v1,v2 v1,v2 的父亲。
可以 dp 这棵有根树,记 f i , x f_{i,x} fi,x 表示操作了前 i i i 轮,最初前缀和为 x x x (相当于这棵树的根权值为 x x x) 的合法方案数。转移为: f i , x = ∑ j = 0 i − 1 ∑ k = 0 i − 1 p × ( i − 1 j ) × ( i − 1 − j k ) × f j , x × f k , x + 1 × f i − j − k − 1 , x + ∑ j = 0 i − 1 ∑ k = 0 i − 1 ( 1 − p ) × ( i − 1 j ) × ( i − 1 − j k ) × f j , x × f k , x − 1 × f i − j − k − 1 , x f_{i,x}=\sum\limits_{j=0}^{i-1} \sum\limits_{k=0}^{i-1} p\times \binom{i-1}{j} \times \binom{i-1-j}{k} \times f_{j,x} \times f_{k,x+1} \times f_{i-j-k-1,x}+\sum\limits_{j=0}^{i-1} \sum\limits_{k=0}^{i-1} (1-p)\times \binom{i-1}{j} \times \binom{i-1-j}{k} \times f_{j,x} \times f_{k,x-1} \times f_{i-j-k-1,x} fi,x=j=0∑i−1k=0∑i−1p×(ji−1)×(ki−1−j)×fj,x×fk,x+1×fi−j−k−1,x+j=0∑i−1k=0∑i−1(1−p)×(ji−1)×(ki−1−j)×fj,x×fk,x−1×fi−j−k−1,x
提取公共部分,记 g i , x = ∑ j = 0 x ( i j ) × f j , x × f i − j , x g_{i,x}=\sum\limits_{j=0}^{x} \binom{i}{j} \times f_{j,x} \times f_{i-j,x} gi,x=j=0∑x(ji)×fj,x×fi−j,x 。
原式相当于 f i , x = ∑ k = 0 j − 1 ( i − 1 k ) × ( p × f k , x + 1 + ( 1 − p ) × f k , x − 1 ) × g i − k − 1 , x f_{i,x}=\sum\limits_{k=0}^{j-1} \binom{i-1}{k} \times (p \times f_{k,x+1} +(1-p) \times f_{k,x-1}) \times g_{i-k-1,x} fi,x=k=0∑j−1(ki−1)×(p×fk,x+1+(1−p)×fk,x−1)×gi−k−1,x 。于是就 O ( n 3 ) O(n^3) O(n3) 解决了。