8-6 ST表与树状数组测试总结
ren_gao_zu · · 个人记录
| question | Expected score | Actual score |
|---|---|---|
| T1 | 100 | 100 |
| T2 | 100 | 100 |
| T3 | 100 | 100 |
| T4 | 100 | 100 |
| T5 | 100 | 88 |
| T6 | 100 | 10 |
| T7 | 100 | 40 |
| T8 | 0 | 0 |
错题总结
T5:
思路
我们可以用ST表来维护前缀和。
我们先来看下这段代码:
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=1e6+5; int n,lg[N],m,f[N][30],a[N],ans,sum[N]; signed main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; sum[i]=sum[i-1]+a[i]; f[i][0]=sum[i]; } for(int i=1;i<=n;i++){ sum[i]=sum[i-1]+a[i]; f[i][0]=sum[i]; } for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1; for(int j=1;j<=25;j++){ for(int i=0;i+(1<<j)-1<=n;i++){ f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]); } } for(int i=1;i<=n;i++){ int l; if(i<=m)l=0; else l=i-m; int len=i-l+1; int j=lg[len]; int mi=min(f[l][j],f[i-(1<<j)+1][j]); ans=max(ans,sum[i]-mi); }cout<<ans; return 0; }看这段代码,是不是感觉能AC?但实际上:
第九个测试点竟然WA了!!!
然后我们下载测试点看一看:
in:
5 -1 -1 -1 -1 -1out:
-1然而,我们上面的那段代码输出的是0,那么我们可以面向数据编程,在最后输出ans改成:
if(ans==0) cout<<-1; else cout<<ans;开个玩笑,下面才是正经的。
我们来思考一下:
题目要求:
1\le k \le m ,也就是小Z必须要吃。而上面的代码是可以选择不吃的,所以会输出0。所以,我们要加上一段:
bool flag=0; int maxn=-1e18; for(int i=1;i<=n;i++){ if(a[i]>=0){ flag=1; break; } maxn=max(maxn,a[i]); } if(flag==0){ cout<<maxn; return 0; }这段代码是什么意思?如果这些蛋糕的幸运值都小于0,但必须要吃,所以就选择吃幸运值大的那一块,不然吃多块蛋糕,幸运值会越来越小。
AC code
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=1e6+5; int n,lg[N],m,f[N][30],a[N],ans,sum[N]; signed main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
sum[i]=sum[i-1]+a[i];
f[i][0]=sum[i];
}
bool flag=0;
int maxn=-1e18;
for(int i=1;i<=n;i++){
if(a[i]>=0){
flag=1;
break;
}
maxn=max(maxn,a[i]);
}
if(flag==0){
cout<<maxn;
return 0;
}
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
f[i][0]=sum[i];
}
for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1;
for(int j=1;j<=25;j++){
for(int i=0;i+(1<<j)-1<=n;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
for(int i=1;i<=n;i++){
int l;
if(i<=m)l=0;
else l=i-m;
int len=i-l+1;
int j=lg[len];
int mi=min(f[l][j],f[i-(1<<j)+1][j]);
ans=max(ans,sum[i]-mi);
}cout<<ans;
return 0;
}
## T6:
### 思路
>维护树状数组,计算每个区间的逆序对个数,然后取最大值。
>
>注意:是最大值,不是求和!!!(~~样例要不要这么水呀~~)
### AC code
```cpp
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=2e5+5;
int n,m,sum[N],ans,cnt;
int b[N],a[N];
map<int,int>mp;
int lowbit(int x){
return x & -x;
}
int get_sum(int x){
int res=0;
while(x){
res+=sum[x];
x-=lowbit(x);
}
return res;
}
void modify(int x,int val){
while(x<=n){
sum[x]+=val;
x+=lowbit(x);
}
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
int idx=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
int x=lower_bound(b+1,b+idx+1,a[i])-b;
ans=max(ans,get_sum(idx)-get_sum(x));
modify(x,1);
}cout<<ans+1;
return 0;
}
T7:
考试结束还差11min的时候想到了二分+ST表,于是在最后2min的时候写出了下面的代码:
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=2e5+5; int n,m,sumf[N],sums[N],f[N][25],lg[N]; struct node{ int f,s; }a[N]; int ans=1e18; bool check(int l,int r){ int fr=sumf[r],fl=sumf[l-1]; if(fr-fl>=m)return 1; return 0; } signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i].f>>a[i].s; sumf[i]=sumf[i-1]+a[i].f; f[i][0]=a[i].s; } for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1; for(int j=1;j<=20;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]); } } for(int i=1;i<=n;i++){ int l=1,r=i,mid; while(l<=r){ mid=l+r>>1; if(check(l,r)){ l=mid+1; int len=i-mid+1,j=lg[len]; ans=min(ans,max(f[l][j],f[i-(1<<j)+1][j])); } else r=mid-1; } }cout<<ans; return 0; }样例也过了,结果只有40分。
但其实,这题只是一道二分答案的题目。
AC code
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=1e6+5; int f[N],s[N],n,m; bool check(int x){ int sum=0; for(int i=1;i<=n;i++){ if(s[i]>x)sum=0; else sum+=f[i]; if(sum>=m)return 1; }return 0; } int ma,ans; signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++)cin>>f[i]>>s[i]; for(int i=1;i<=n;i++)ma=max(ma,s[i]); int l=1,r=ma,mid; while(l<=r){ mid=l+r>>1; if(check(mid)){ r=mid-1; ans=mid; } else l=mid+1; }cout<<ans; return 0; }