PPT上面的好多题都做不了,ACWING上的题要报名才能做,Codeforces 1000C搜不出来,就做了剩下的,不过二维差分前缀和早就掌握了
ACWING-797. 差分 超级模板
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <bits/stdc++.h> using namespace std ; const int MAXN=1e5 +100 ;int val[MAXN],cha[MAXN];int main () { int n,m; cin >>n>>m; for (int i=1 ;i<=n;i++) cin >>val[i]; while (m--){ int l,r,c; cin >>l>>r>>c; cha[l]+=c; cha[r+1 ]-=c; } for (int i=1 ;i<=n;i++){ cha[i]+=cha[i-1 ]; if (i!=n) cout <<val[i]+cha[i]<<" " ; else cout <<val[i]+cha[i]<<endl ; } return 0 ; }
洛谷-海底高铁 算出每两个城市的往返次数,然后贪心一下,找到最小的,这道题之前做过,当时第一次就AC了,这道题应该不难
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std ; typedef long long ll; const int MAXN=1e5 +100 ;long long A[MAXN],B[MAXN],C[MAXN],X[MAXN],cha[MAXN];int main () { ios; int n,m; cin >>n>>m; for (int i=1 ;i<=m;i++) cin >>X[i]; for (int i=1 ;i<=n-1 ;i++){ cin >>A[i]>>B[i]>>C[i]; A[i]+=A[i-1 ]; B[i]+=B[i-1 ]; } for (int i=1 ;i<=m-1 ;i++){ int l=min(X[i],X[i+1 ]); int r=max(X[i],X[i+1 ]); cha[l]++; cha[r]--; } ll sum=0 ; for (int i=1 ;i<=n-1 ;i++){ cha[i]+=cha[i-1 ]; ll t1=cha[i]*(A[i]-A[i-1 ]); ll t2=cha[i]*(B[i]-B[i-1 ])+C[i]; sum+=min(t1,t2); } cout <<sum<<endl ; return 0 ; }
倍增&&ST表 首先明白倍增是一种思想而不是模板,它与ST并没有必然的联系,不是主要有倍增就必然出现ST,做倍增题一定要明白是对什么倍增的,通常就是对区间长度或者距离倍增,使用倍增通常有(RMQ)即区间最值查询(第二道题),以及LAC这个还没学,ST表的核心是找到ST的递推关系,从小往大推,直到打完所有表,时间复杂度是O(mlogn),m为结点数量,n是走的步数(2^0,2^1…), 2^20
就已经超过 1e6
了,2^64
大于 1e20
,所以logn是非常小的,最多几十次,复杂度记乎可以看成O(N*10)
AtCoder - abc167_d 一道图上倍增的题目,别看这个1e18很大,它的log级别比64还小,用倍增做时间复杂度变成了O(NlongM),就是2e6的样子 这里st表很直接,储存的就是跳了N此后到达位置,特别特别需要注意的是查询千万不能用( 1 << i ),这是特别大的数字,我不明白为啥m是ll,就算把( 1 << i )转化为ll类型再进行与操作还是不行,ll不是64位的吗?范围应该是够的,奇怪,不过以后最好让m右移这样不会爆int,当然也可以用while遍历每一位
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> #include <iostream> #include <stdlib.h> #include <cmath> using namespace std ; typedef long long ll;const int maxn=2e5 +100 ;int st[maxn][70 ],a[maxn];int n,pos=1 ;ll m; void bz () { int len=log2(m); for (int i=1 ;i<=n;i++) st[i][0 ]=a[i]; for (int i=1 ;i<=len;++i){ for (int j=1 ;j<=n;++j){ st[j][i]=st[st[j][i-1 ]][i-1 ]; } } } int main () { cin >>n>>m; for (int i=1 ;i<=n;++i) cin >>a[i]; bz(); for (int i=0 ;i<64 ;i++){ if (1 &(m>>i)){ pos=st[pos][i]; } } cout <<pos<<endl ; }
ACWING-1270. 数列区间最大值 一道模板RMQ题目,这道题ST储存的是每一段区间的最值,倍增的是区间长度,就这道题而言,一段区间的最大值可以由这段区间从中间分开的两端区间的最值的合并,而且每一个数都是可以用2进制表示的,那么就一定用st表中的数相加得到
st[i][j]表示从i这一点开始数2^j^个数的最值,即往后数2^(j-1)^个数的最值
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std ; const int MAXN=1e5 +100 ;int n,m;int st[MAXN][22 ],a[MAXN];void init () { for (int i=1 ;i<=n;i++) st[i][0 ]=a[i]; for (int j=1 ;(1 <<j)<=n;j++){ for (int i=1 ;i+(1 <<j)-1 <=n;i++){ st[i][j]=max(st[i][j-1 ],st[i+(1 <<j-1 )][j-1 ]); } } return ; } int main () { ios; cin >>n>>m; for (int i=1 ;i<=n;i++) cin >>a[i]; init(); while (m--) { int r,l; cin >>l>>r; int k=log2(r-l+1 ); cout <<max(st[l][k],st[r-(1 <<k)+1 ][k])<<endl ; } }
牛客竞赛- 15429 倍增 这道题卡了一天,还是由于我对倍增理解不深,这道题是对往后分2^j^段倍增的,ST表储存的是分成2^j^段对多能到达的距离,讲解全在代码里了
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) using namespace std ; const int MAXN=1e6 +100 ;long long n,m,k;long long st[MAXN][21 ],book[MAXN],sum[MAXN];void init () { for (int i=1 ;i<=n;i++){ st[i][0 ]=upper_bound(sum+1 ,sum+1 +n,sum[i-1 ]+k)-sum; } for (int i=1 ;(1 <<i)<=n;i++) for (int j=1 ;j<=n;j++){ st[j][i]=st[st[j][i-1 ]][i-1 ]; } } int query (int l,int r) { int ans=1 ; for (int i=20 ;st[l][0 ]<=r;i--){ if (st[l][i]<=r&&st[l][i]){ l=st[l][i]; ans+=(1 <<i); } } return ans; } int main () { ios; cin >>n>>m>>k; for (int i=1 ;i<=n;i++){ int t; cin >>t; sum[i]=t+sum[i-1 ]; book[i]=book[i-1 ]+(t>k); } init(); while (m--){ int l,r; cin >>l>>r; if (book[r]-book[l-1 ]>0 ) cout <<"Chtholly" <<'\n' ; else cout <<query(l,r)<<"\n" ; } return 0 ; }
做了这三道倍增题感觉对倍增有了新的认识,但是我还是处理不好ST和倍增的关系,经常处理不好ST之间的关系,真的感觉自己好菜😢