专栏文章
8-6 ST表与树状数组测试总结
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miohcm0e
- 此快照首次捕获于
- 2025/12/02 19:13 3 个月前
- 此快照最后确认于
- 2025/12/02 19:13 3 个月前
| 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:
思路
CPP我们可以用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:
CPP5
-1 -1 -1 -1 -1
out:
CPP-1
CPP然而,我们上面的那段代码输出的是0,那么我们可以面向数据编程,在最后输出ans改成:
if(ans==0)
cout<<-1;
else cout<<ans;
CPP开个玩笑,下面才是正经的。我们来思考一下:题目要求:,也就是小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
CPP#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:
CPP考试结束还差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
CPP#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;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...
