这个周首先复习了暑假看的树状数组
#define lowbit(x) ((x)&-(x))
void add(int x,int d) // 初始化(或更改树状数组),如果想初始化那就是多次更改
{
while(x<=n)
{
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x) //求数组和的优化
{
int sum=0;
while(x>0)
{
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
P1168 中位数
给出一段序列,要求对于每奇数个数就要求一次中位数,n最大有10的5次方。
这个题首先想到的就是sort排序,但是每次要求中位数的时候就sort一次肯定就超时了,自己写了个二分答案也超时了…看到题解有大佬用动态数组+二分水过去了,对于每个数字,用二分找到它应该在的位置,插入到前面的数组里,每次直接输出数组中间的数就可以了(stl的二分,水题十分好用)。
#includeusing namespace std; vector a; int main() { int n,i,x; cin>>n; for(i=1;i<=n;i++) { cin>>x; a.insert(upper_bound(a.begin(),a.end(),x),x); if(i%2!=0) { cout< B. Hemose Shopping
给出几组数据,对于每组数据有数组大小n,整数x,数组的数字。每个数组,如果|ai-aj|>=x,那么可以交换数组中的这两个数字,能不能将它们交换成升序?用yes和no代表输出。
纯思维题,但是想了很久。如果数组的大小除2要大于等于x,就肯定可以交换,如果小于x,我们还要考虑这个数组原本是否有序。如果这个数组在n-x到x的元素原来就有序,那么它仍可以交换;如果无序,那么就没办法了。#includeusing namespace std; typedef long long ll; int a[100001]; int b[100001]; int main() { int i,n,x,t; cin>>t; while(t--) { cin>>n>>x; for(i=0;i >a[i]; b[i]=a[i]; } if(n/2>=x) {cout<<"YES"< P1020 导弹拦截
通俗点说就是给出一段导弹的高度,第一个输出求出最长不上升子序列的长度,第二个输出最长上升子序列的长度。
想要得到满分的话要用复杂度为n*log2 n的方法,我用了二分查找和树状数组两种方法做出来了。
1.二分查找
网上有stl的二分和手写二分两种方法,我这里用的是手写的二分
建议不太懂的直接记模板,通过这种写法最长上升子序列、不上升子序列、下降子序列、不下降子序列只要改两个符号就可以实现转换。#includeusing namespace std; int a[100001],f[100001]; int ans=0; int main() { int n=0,x; while(cin>>x) { n++; a[n]=x; } f[0]=999999; for(int i=1; i<=n; ++i) { if(a[i]==0) continue; if(f[ans]>=a[i]) //想要改成最长下降子序列把等号去掉就行 f[++ans]=a[i]; else { int l=0,r=ans,mid; while(l<=r) { mid=(l+r)/2; if(f[mid]=a[i]) r=mid-1; else l=mid+1; } if(l!=0) f[l]=a[i]; } } cout< 2.树状数组
虽然很久以前就学了树状数组,但是现在依然还是不怎么会用,看完大佬的代码我只能说是:妙啊,真是妙啊!
这里就解释一下最长上升子序列吧,另一个直接倒转其实就可以了。树状数组有两个函数,一个是用来初始化(或更改)树状数组的函数,另一个是通过树状数组来优化答案的函数。我们运用dp的思想,把导弹高度h作为树状数组的下标,用树状数组的值来记录最长的长度。对一个高度进行操作,我们要求得这个高度之前的最长上升长度,遍历树状数组记录下最大值就行。然后将这个高度插入树状数组,因为是最长上升子序列,所以树状数组下标比这个高度高的长度都要+1,然后求这个高度的最长子序列长度是多少,更改树状数组。控制范围,我们提前记录下导弹高度的最小值和最大值。#include#define lowbit(x) ((x)&-(x)) using namespace std; int h[100001],shangsheng[100001],xiajiang[100001]; int maxx=0,n=0,m,minn=999999; int zuichang(int x) //最长上升子序列的计算函数 { int res=0; while(x>=minn) //求这个高度之前的最长上升长度是多少 { res=max(shangsheng[x],res); x=x-lowbit(x); } return res; } void addzuichang(int x,int y) //最长上升子序列树状数组的插入函数 { while(x<=maxx) //比这个高度高的都要重新更改一下树状数组的值 { shangsheng[x]=max(shangsheng[x],y); x=x+lowbit(x); } } int buxiajiang(int x) { int res=0; while(x<=maxx) { res=max(res,xiajiang[x]); x=x+lowbit(x); } return res; } void addbuxiajiang(int x,int y) { while(x>=minn) { xiajiang[x]=max(xiajiang[x],y); x=x-lowbit(x); } } int main() { int i; int ans1=0,ans2=0; while(cin>>m) { n++; h[n]=m; maxx=max(maxx,m); //提前求出范围 minn=min(minn,m); } for(i=1;i<=n;i++) { int x=zuichang(h[i])+1; //用函数求出的是它之前的最长长度,算上它自己还要+1 int y=buxiajiang(h[i])+1; ans1=max(ans1,y); ans2=max(ans2,x); //求出求过的最大值 addzuichang(h[i]+1,x);//因为是严格上升,高度还要+1 addbuxiajiang(h[i],y);//不上升就行了,比这个高度低的都可以更改 } cout<



