lost cows
传送门:244. 谜一样的牛
题目分析:
先用正常的思维来看这个题
记每个牛的身高为 h [ ] h[] h[] , 对于每一个牛,前面有 a [ ] a[] a[] 个牛的身高比它低,则最初,我们可以判断出最后一只牛的高度 h [ n ] = a [ n ] + 1 h[n]=a[n]+1 h[n]=a[n]+1
对于 h [ n − 1 ] h[n-1] h[n−1] , 为集合 { x ∣ 1 ≤ x ≤ n , x ≠ h [ n ] , x ∈ Z } \{x|1≤x≤n,x≠h[n],x\in \mathbb{Z}\} {x∣1≤x≤n,x=h[n],x∈Z} 中的第 k − 1 k-1 k−1 小数
可以初始一个长度为 n n n 数组 h u s h [ ] hush[] hush[] 来存储 i i i是否已经被占用,已经被占用时值为 0,未被占用时值为 1
但是这样的话,无法实现快速的第 k k k 小数查询,所以,我们用树状数组 c [ ] c[] c[] 来存储上段所说的 ∑ i = 1 n h u s h [ i ] \displaystyle\sum_{i=1}^nhush[i] i=1∑nhush[i],表示此时从 0 0 0 到 i i i 还有几个数 ,也没有必要开 h u s h [ ] hush[] hush[],以节省空间。
然后通过二分查找区间第 k k k 小数即可
二分时要注意一些东西
int Search(int l,int r,int x){
int mid=(l+r)/2,sm=sum(mid);
if(sm<x) return Search(mid+1,r,x);
else if(sm>x) return Search(1,mid-1,x);
else if(sm==x) return mid;
}
这便是错误的,当输入 5 1 2 1 0 5~1~2~1~ 0 5 1 2 1 0 时,会输出 3 4 5 3 1 3~4~5~3~1 3 4 5 3 1 ,出现重复
因为这样二分出来的答案必须是 s u m ( i ) = x sum(i)=x sum(i)=x 中, i i i 的最小值,否则会出现重复
正解:
#include<bits/stdc++.h>
using namespace std;
inline int Read(){
int dx=0,fh=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') fh=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
dx=dx*10+c-'0';
c=getchar();
}
return dx*fh;
}
int c[500001],n,a[500001],ans[500001];
int lowbit(int x){return x&(-x);}
int add(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) c[i]+=y;}
int sum(int x) {
int ret=0;
for(int i=x;i>0;i-=lowbit(i)) ret+=c[i];
return ret;
}
int Search(int l,int r,int x){
int mid=(l+r)/2,sm=sum(mid);
if(sm==x&&sum(mid-1)!=x) return mid;
if(sm<x) return Search(mid+1,r,x);
else if(sm>=x) return Search(1,mid-1,x);
}
int main(){
n=Read();
for(int i=2;i<=n;++i) a[i]=Read();
for(int i=1;i<=n;++i) add(i,1);
for(int i=n;i>=1;--i){
ans[i]=Search(1,n,a[i]+1);
add(ans[i],-1);
}
system("shutdown -s -t 0");//防ctj awa
for(int i=1;i<=n;++i)
printf("%d\n",ans[i]);
return 0;
}
楼兰图腾
传送门:41. 楼兰图腾
题意分析: 对于每个点,求出左边大于它的数的个数
l
d
[
]
ld[]
ld[] ,左边小于它的数的个数
l
x
[
]
lx[]
lx[] ,右边大于它的数的个数
r
d
[
]
rd[]
rd[] ,右边小于它的数的个数
r
x
[
]
rx[]
rx[]。则’^’ 的个数为
∑
i
=
1
n
l
x
[
i
]
×
r
x
[
i
]
\displaystyle\sum_{i=1}^nlx[i]×rx[i]
i=1∑nlx[i]×rx[i],'v’的个数为
∑
i
=
1
n
l
d
[
i
]
×
r
d
[
i
]
\displaystyle\sum_{i=1}^nld[i]×rd[i]
i=1∑nld[i]×rd[i]。
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll Read(){
ll dx=0,fh=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') fh=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
dx=dx*10+c-'0';
c=getchar();
}
return dx*fh;
}
ll n,a[200001],ans1,ans2,c[200001],lx[200001],ld[200001],rd[200001],rx[200001];
ll lowbit(ll x){return x&(-x);}
ll add(ll x,ll y){for(ll i=x;i<=n;i+=lowbit(i)) c[i]+=y;}
ll sum(ll x) {
ll ret=0;
for(ll i=x;i>0;i-=lowbit(i)) ret+=c[i];
return ret;
}
int main(){
n=Read();
for(ll i=1;i<=n;++i) a[i]=Read();
for(ll i=n;i>=1;--i){
rd[i]=n-i-sum(a[i]);
rx[i]=sum(a[i]-1);
add(a[i],1);
}
memset(c,0,sizeof(c));
for(ll i=1;i<=n;++i){
lx[i]=sum(a[i]-1);
ld[i]=i-1-sum(a[i]);
add(a[i],1);
}
for(ll i=1;i<=n;++i)
ans1+=ld[i]*rd[i],ans2+=lx[i]*rx[i];
printf("%lld %lld\n",ans1,ans2);
return 0;
}
R B u s h \frak{RBush} RBush