D1. Optimal Subsequences (Easy难度到hard难度)
\(\color{Red}题目大意\)
\(给出一个长n序列,要求每次选出一个长k的子序列,使得\)
\(子序列的元素和最大且字典序最小,问第pos个元素是多少.\)
\(\color{orange}对于easy版本,我们可以很暴力的写\)
\(直接把元素按照大小关系存进vector\)
\(每次选取最大的元素,如果有多个就选最前面的那个\)
\(你可能有疑问,为什么最大的元素选最前面的呢?\)
\(当取完这种元素时,对答案没有影响,都要选\)
\(如果没取完这种元素,那么这种元素是所取的最小元素,肯定选最前面的\)
\(元素确定了,按照先后顺序排个序,就好了\)
#include <bits/stdc++.h>
using namespace std;
const int maxn=209;
int n,top,k,t,pos,tot;
struct p{
int x,num;
}a[209],b[209];
bool big(p a,p b){
return a.x<b.x;
}
bool zi(p a,p b){
return a.num<b.num;
}
vector<p>vec[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>a[i].x;
a[i].num=i;
}
sort(a+1,a+1+n,big);
vec[++top].push_back(a[1]);
for(int i=2;i<=n;i++)
{
if(a[i].x==a[i-1].x) vec[top].push_back(a[i]);
else vec[++top].push_back(a[i]);
}
for(int i=1;i<=top;i++) sort(vec[i].begin(),vec[i].end(),zi);
cin>>t;
while(t--)
{
cin>>k>>pos;
tot=0;
int w=0;
for(int i=top;i>=1;i--)
{
for(int j=0;j<vec[i].size();j++)
{
b[++w]=vec[i][j];
if(w==k) break;
}
if(w==0) break;
}
sort(b+1,b+1+k,zi);
cout<<b[pos].x<<endl;
}
}
\(\color{Red}hard难度\)
\(按照上面的的easy版本,对于每个k要取的数是固定的\)
\(而且长度为k的序列只比k-1的最大序列多了一个数而已\)
\(于是我们离线操作,把所有询问存起来,按照k小到大排序\)
\(先处理k最小的,选出最大的k个元素,放在树状数组上标记使用过\)
\(然后我们就二分出哪个点刚好使用了pos个数字,就是答案\)
\(\color{green}非常巧妙\)
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+9;
int n,b[maxn],m,ans[maxn];
struct p{
int x,num;
bool operator < (const p&tmp ) const{
return this->x==tmp.x?this->num<tmp.num:this->x>tmp.x;
}
}a[maxn];
struct quest{
int k,pos,index;
bool operator < (const quest &tmp) const{
return this->k<tmp.k;
}
}q[maxn];
class binary_tree
{
private:
int sumn[maxn];
int lowbit(int x){return x&(-x);}
public:
void update(int x,int k){
while(x<=n) sumn[x]+=k,x+=lowbit(x);
}
int ask(int x){
int ans=0;
while(x) ans+=sumn[x],x-=lowbit(x);
return ans;
}
}tree;
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x;
a[i].num=i;
b[i]=a[i].x;
}
sort(a+1,a+1+n);
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>q[i].k>>q[i].pos;
q[i].index=i;
}
sort(q+1,q+1+m);
int cur=1;
for(int i=1;i<=m;i++)
{
for(;cur<=q[i].k;cur++) tree.update(a[cur].num,1);
int l=1,r=n;
while(r>l)
{
int mid=l+r>>1;
if(tree.ask(mid)>=q[i].pos) r=mid;
else l=mid+1;
}
ans[q[i].index]=b[r];
}
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
}
int main()
{
solve();
}