题意:n张牌,如果当前不是最小值,将其放到最底下,否则拿掉,问最少需要多少步;
思路:就是模拟,然后对于求答案的时候需要更新,对于未拿走的牌,标记为1,否则为0,利用树状数组快速求区间和,即求到下张牌的距离;
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cmath> #include<string> #include<queue> #include<algorithm> #include<stack> #include<cstring> #include<vector> #include<list> #include<set> #include<map> using namespace std; #define LL long long #define pi (4*atan(1.0)) #define eps 1e-14 #define bug(x) cout<<"bug"<<x<<endl; const int N=1e5+10,M=2e6+10,inf=1e9+10; const LL INF=1e18+10,mod=1e9+7; struct AYT { int tree[N]; int lowbit(int x) { return x&-x; } void update(int x,int c) { while(x<N) { tree[x]+=c; x+=lowbit(x); } } int query(int x) { int ans=0; while(x) { ans+=tree[x]; x-=lowbit(x); } return ans; } } tree; int a[N],n; vector<int>pos[N]; int check(int i,int x) { int s=0,e=pos[i].size()-1,ans=-1; while(s<=e) { int mid=(s+e)>>1; if(pos[i][mid]>x) { ans=mid; e=mid-1; } else s=mid+1; } return ans; } int dis(int s,int e) { if(s==-1)return tree.query(e); if(s<e)return tree.query(e)-tree.query(s); return tree.query(n)-tree.query(s)+tree.query(e); } int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); tree.update(i,1); pos[a[i]].push_back(i); } int pre=-1; LL ans=0; for(int i=1; i<=100000; i++) { if(!pos[i].size())continue; int v=check(i,pre); for(int j=max(0,v); j<pos[i].size(); j++) { ans+=dis(pre,pos[i][j]); pre=pos[i][j]; tree.update(pre,-1); //cout<<pre<<" "<<ans<<endl; } for(int j=0; j<v; j++) { ans+=dis(pre,pos[i][j]); pre=pos[i][j]; tree.update(pre,-1); //cout<<pre<<" "<<ans<<endl; } } printf("%lld\n",ans); return 0; }