专栏文章
8-6 ST表与树状数组总结
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miohcn0t
- 此快照首次捕获于
- 2025/12/02 19:13 3 个月前
- 此快照最后确认于
- 2025/12/02 19:13 3 个月前
考试情况
| 题目编号 | 分数 |
|---|---|
| T1 | 100 |
| T2 | 100 |
| T3 | 100 |
| T4 | 100 |
| T5 | 100 |
| T6 | 10 |
| T7 | 60 |
| T8 | 10 |
总分数:580 本来如果T6不把暴力改成逆序对可以多拿50pts,那么这样直接number1--->630pts
T6 P4378 [USACO18OPEN] Out of Sorts S
考场代码
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int c[N],n,m,a[N],b[N];
//bool cmp(int a,int b)
//{
// return a>b;
//}
int lowbit(int x)
{
return x&-x;
}
int get_ans(int x)
{
int res=0;
while(x)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
void modify(int x,int val)
{
while(x<=n)
{
c[x]+=val;
x+=lowbit(x);
}
return ;
}
map<int,int> mp;
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];
// int cnt=0;
// bool flag=0;
// while(!flag)
// {
// flag=1;
// cnt++;
// for(int i=1;i<n;i++)
// {
// if(a[i+1]<a[i])
// {
// swap(a[i+1],a[i]);
// flag=0;
// }
// }
// }
// cout<<cnt;
int sum=0,cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++)
{
if(b[i]!=b[i-1])mp[b[i]]=++cnt;
}
for(int i=n;i>=1;i--)
{
sum+=get_ans(mp[a[i]]-1);
modify(mp[a[i]],1);
}
cout<<sum;
return 0;
}
考场错误
想到了逆序对,可是逆序对是任意两个点,但是本题的要求是说必须是两个相邻的数。
正确思路
其实可以用结构体+sort解决
我们可以观察伪代码,是从小到大排序,那么我们的cmp函数首先可以先写出这个步骤
x.num<y.num但是只用这一个判断只能得到80pts,所以我们再观察题目,由于本题一个数会出现多次,所以我们在排序时,还要再判断等于的情况,若等于则要让原位置后的位置排序时前
然后排完序后,因为在最后一次修改后,sorted的值依然是0 .所以要再刷一次,也就是说答案要+1。
AC代码
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
struct node
{
int id,num;
}a[N];
bool cmp(node x,node y)
{
return x.num<y.num||(x.num==y.num&&x.id<y.id);
}
signed main()
{
int n,ans=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].num;
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)ans=max(ans,a[i].id-i);
cout<<ans+1;
return 0;
}
T7 P4085 [USACO17DEC] Haybale Feast G
考场代码
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int a[N],b[N];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
int minn=1e18;
for(int i=1;i<=n;i++)
{
int sum=0,ans=0;
for(int j=i;j<=n;j++)
{
sum+=a[j];
ans=max(ans,b[j]);
if(sum>=m)
{
minn=min(minn,ans);
break;
}
}
}
cout<<minn;
return 0;
}
其实是用暴力写的,所以没什么值得调的,直接将正确思路
正确思路
二分答案
这道题目使用瞪眼法可以发现,其实具有单调性,我们可以用check来查找连续的一段区间能否满足M,
AC代码
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5;
int fw[N],ld[N],n,m;
bool check(int x)
{
int sum=0;
for(int i=1;i<=n;i++)
{
if(ld[i]>x)sum=0;
else sum+=fw[i];
if(sum>=m)return 1;
}
return 0;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
int maxx=-1e18;
for(int i=1;i<=n;i++)
{
cin>>fw[i]>>ld[i];
maxx=max(maxx,ld[i]);
}
int l=1,r=maxx,ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
r=mid-1;
ans=mid;
}
else l=mid+1;
}
cout<<ans;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...