Codeforces Round #424 (Div. 2, )-树状数组|线段树-E. Cards Sorting

来源:互联网 发布:简述单片机的引脚功能 编辑:程序博客网 时间:2024/06/04 18:55

、http://codeforces.com/contest/831/problem/E
给定一副扑克,规则如下
1 输入的数组是从顶到尾的顺序。
2 每次从顶上拿扑克,当这个值在当前排堆中是最小的(可能会重复,不过没关系),我们就把他抽出来。然后继续。如果不是,我们就把他放在牌底,直到所有的牌全部都拿掉之后就完事了,问你他所需要的操作数是多少。
数据范围 扑克数量 100000。
我们可以发现啊,无论怎么搞,顺序都是固定的,我们可以用直接模拟的方法来写。不过考虑到这个扑克有点大啊。
我们肯定可以确定顺序是 从最小的扑克开始,如果有相同的,那么就从最近离牌顶的牌开始拿。我们可以弄一个集合,把所有相同的扑克,都弄到一个数组里,a[i]存的是所有价值为i的扑克的位置。然后我们遍历这个数组,从小到大就可以了。
需要注意的是,没开始一个新i,那么扑克的位置在上一个i的最大的位置。
我们用 树状数组来模拟这个过程(是否存在这个数了。)
注意树状数组是从1开始的。。
明白点

#include <bits/stdc++.h>using namespace std;const int maxn=100005;int tree[maxn];vector<int>v[maxn];int pre;int t;typedef long long ll;bool cmp2(int a,int b){   int x=(a-pre+t)%t;   int y=(b-pre+t)%t;   return x<y;}int lowbit(int x){  return x&(-x);}//得到lowbit;void update(int x,int n){    while(x<maxn){        tree[x]+=n;         x+=lowbit(x);//单点更新    }}int getsum(int x){    int ans=0;//区间求和    while(x>0){        ans+=tree[x];        x-=lowbit(x);    }    return ans;}int main(){    int a;    scanf("%d",&t);    for(int i=1;i<=t;i++){        scanf("%d",&a);        v[a].push_back(i);        update(i,1);//更新,位置    }        pre=0;        for(int i=1;i<=100000;i++){            if(v[i].size()){            sort(v[i].begin(),v[i].end(),cmp2);            pre=v[i][v[i].size()-1];}        }//类似一个  拓扑序??        int pre=1;        ll ans=0;        for(int i=1;i<=100000;i++){            if(!v[i].size()) continue;            for(int j=0;j<v[i].size();j++){                int now=v[i][j];                if(now>pre)                ans+=getsum(now)-getsum(pre);                else                   ans+=getsum(t-1)-(getsum(pre)-getsum(now));                pre=now;                update(now,-1);//删除啦            }        }        printf("%lld\n",ans);    return 0;}

线段树当然也可以了,毕竟线段树也是66哒

阅读全文
1 0
原创粉丝点击