XCSY暑期集训模拟赛2T3善良
暴力(50pts)
对于每个询问,遍历\([l,r]\),统计其中k的数量,时间复杂度为\(O(nm)\)。
for(int i=1;i<=n;i++) cin>>a[i];
while(m--){
cin>>l>>r>>k;
int ans=0;
for(int i=l;i<=r;i++){
if(a[i]==k) ans++;
}
cout<<ans<<'\n';
}
二分(100pts)
用\(map[i]\)统计数字\(i\)出现的所有位置,每个\(map[i](1 \leq i \leq n)\)都是单调递增的。
对于每个询问,在\(map[k]\)中二分找到第一个\(\geq l\)和最后一个\(\leq r\)的数的位置,计算其中共包含多少个数即可(包含左右端点,具体见代码)

map<int,vector<int> >mp;//mp[i]表示数字i出现的所有位置
for(int i=1;i<=n;i++){
cin>>a;
mp[a].push_back(i);
}
while(m--){
cin>>l>>r>>k;
vector<int>v=mp[k];
if(v.empty()||v[0]>r||v[v.size()-1]<l){//没有符合要求的数
cout<<0<<'\n';
continue;
}
int left=0,right=v.size()-1;
while(left<right){
int mid=left+right>>1;
if(v[mid]<l) left=mid+1;
else right=mid;
}
int x=right;//找第一个≥l的数的位置
if(v[v.size()-1]<=r){//所有x以后的数均≤r,最后一个≤r的数的位置就是最后一个位置
cout<<v.size()-x<<'\n';//左端点为x,右端点为v.size()-1,共有v.size()-1-x+1=v.size()-x个数
}else{
left=right,right=v.size()-1;
while(left<right){
int mid=left+right>>1;
if(v[mid]>r) right=mid;
else left=mid+1;
}//找第一个>r的数的位置,减1就是最后一个≤r的数的位置
cout<<left-x<<'\n';//左端点为x,右端点为left-1,共有left-1-x+1=left-x个数
}
}
浙公网安备 33010602011771号