Codeforces #831E: Cards Sorting 题解

来源:互联网 发布:知乎 碧桂园森林城市 编辑:程序博客网 时间:2024/05/22 16:44

题目里面的将第一张放到牌堆最下面看起来很玄乎,其实就是摸牌的时候循环摸牌

我们的目标是在摸完第i张牌后,迅速判断要摸到第i+1张牌要再摸几次

于是我们可以用线段树来维护一个区间内还有多少牌没有被扔出去,这样每次做一个区间查询,扔牌时做一个单点修改就好

这题还有一个难点是如何确定牌的大小次序

对于序号不同的牌,当然是序号小的靠前

对于序号相同的牌,要看上一种牌的最后一张在哪里,然后按照

1.在它后面的一定比在它前面的小

2.都在它后面的离它越近越小

3.都在它前面的离它越远越小

进行排序

注意:牌上的序号是<=1e5,不是n

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <cmath>#include <algorithm>#include <cstdlib>#include <utility>#include <map>#include <stack>#include <set>#include <vector>#include <queue>#include <deque>#include <bitset>#define x first#define y second#define mp make_pair#define pb push_back#define LL long long#define Pair pair<int,int>#define LOWBIT(x) x & (-x)using namespace std;const int zero_stand=1500;const int MOD=1e9+7;const int INF=0x7ffffff;const int magic=348;vector<int> v[100048];int stand;struct node{int left,right;int sum;}tree[300048];void build(int cur,int left,int right){tree[cur].left=left;tree[cur].right=right;tree[cur].sum=right-left+1;if (left!=right){int mid=(left+right)>>1;build(cur*2,left,mid);build(cur*2+1,mid+1,right);}}void update(int cur,int pos){if (tree[cur].left==tree[cur].right){tree[cur].sum=0;return;}int mid=(tree[cur].left+tree[cur].right)>>1;if (pos<=mid) update(cur*2,pos); else update(cur*2+1,pos);tree[cur].sum=tree[cur*2].sum+tree[cur*2+1].sum;}int query(int cur,int left,int right){if (left>right) return 0;if (left<=tree[cur].left && tree[cur].right<=right){return tree[cur].sum;}int mid=(tree[cur].left+tree[cur].right)>>1;int res1=0,res2=0;if (left<=mid) res1=query(cur*2,left,right);if (mid+1<=right) res2=query(cur*2+1,left,right);return res1+res2;}int n;Pair a[100048];int pos[100048];bool cmp(int x,int y){if (x-stand>0 && y-stand<0 || x-stand<0 && y-stand>0) return x-stand>y-stand;if (x-stand>0 && y-stand>0) return x-stand<y-stand;if (x-stand<0 && y-stand<0) return x-stand<y-stand;}int main (){int i,j;scanf("%d",&n);for (i=1;i<=n;i++){scanf("%d",&a[i].x);a[i].y=i;v[a[i].x].pb(i);}int t=1;while (v[t].size()==0) t++;sort(v[t].begin(),v[t].end());stand=v[t].back();t++;do{while (t<=100000 && v[t].size()==0) t++;if (t>100000) break;sort(v[t].begin(),v[t].end(),cmp);stand=v[t].back();t++;}while (t<=100000);build(1,1,n);int top=0;for (i=1;i<=100000;i++)if (v[i].size()!=0)for (j=0;j<v[i].size();j++)pos[++top]=v[i][j];pos[0]=0;LL ans=0;int cnt;for (i=1;i<=n;i++){if (pos[i-1]+1<=pos[i]){cnt=query(1,pos[i-1]+1,pos[i]);ans+=cnt;}else{cnt=query(1,pos[i-1]+1,n);cnt+=query(1,1,pos[i]);ans+=cnt;}update(1,pos[i]);}cout<<ans<<endl;return 0;}


原创粉丝点击