题意:
有个球的圈圈。三种操作:逆时针转一个,顺时针转一个,丢掉手中的那个的同时顺时针的球到你的手里。每个操作都花费一秒。告诉你要求的出圈顺序,求最小花费时间。注:开始在手中的球为1.
解:
线段树和树状数组都可。树状数组很蛋疼。建议我以后用线段树。开始为什么不用线段树是因为怕自己搞不出相对坐标和绝对坐标。凡是二分的树状数组能不写就不写。
这个是用set代替二分的代码,建议以后迫不得已要用二分的时候就用set。
/*
Pro: 0
Sol:
date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 100010
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
int n,now,c[maxn],pre,suf,alre,out,in;
__int64 ans;
struct query{
int id, ord;
}q[maxn];
bool cmpx(query a,query b){
return a.ord < b.ord;//ord是时间
}
int getsum(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= (pos & -pos);
}return sum;
}
void modify(int pos){
while(pos <= n){
c[pos] += 1;
pos += (pos & -pos);
}
}
set <int> S;
set <int> :: iterator it;
int main(){
while(~scanf("%d",&n) && n){
memset(c,0,sizeof(c));//0 表示在手里, 1 表示已经出去了 id建边
S.clear();
for(int i = 1; i <= n; i ++){
scanf("%d",&q[i].ord);
q[i].id = i;
S.insert(i);
}
sort(q + 1, q + n + 1, cmpx); now = 1; ans = 0; alre = 0;
for(int i = 1; i <= n; i ++){
// cout<<now<<" "<<q[i].id<<endl;
if(now > q[i].id) {
pre = q[i].id;
suf = now;
}else{
pre = now;
suf = q[i].id;
}
pre = pre - getsum(pre);//表示前面有多少个0,多少个还在,包括本身
suf = suf - getsum(suf);
in = suf - pre;
out = n - alre - in;
ans+=min(in,out)+1;
alre ++;
if(alre==n)break;
S.erase(q[i].id);
if(S.lower_bound(q[i].id)!=S.end())
{
it=S.lower_bound(q[i].id);
}
else
{
it=S.lower_bound(0);
}
now = *it ;
}
cout<<ans<<endl;
}
return 0;
}
这个是改出来的二分。老娘虚脱了。
/*
Pro: 0
Sol:
date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 100010
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
int n,now,c[maxn],pre,suf,alre,out,in;
__int64 ans;
struct query{
int id, ord;
}q[maxn];
bool cmpx(query a,query b){
return a.ord < b.ord;//ord是时间
}
int getsum(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= (pos & -pos);
}return sum;
}
void modify(int pos){
while(pos <= n){
c[pos] += 1;
pos += (pos & -pos);
}
}
int bs(int l,int r)
{
int mid,flag=l;
while(l + 1< r)
{
mid=(l+r)>>1;
if(getsum(mid)-getsum(l)==mid-l)
{
l=mid;
}
else
{
r=mid;
}
}
if(getsum(l)-getsum(flag)==l-flag)
{
return r;
}
return l;
}
int main(){
while(~scanf("%d",&n) && n){
memset(c,0,sizeof(c));//0 表示在手里, 1 表示已经出去了 id建边
for(int i = 1; i <= n; i ++){
scanf("%d",&q[i].ord);
q[i].id = i;
}
sort(q + 1, q + n + 1, cmpx); now = 1; ans = 0; alre = 0;
for(int i = 1; i <= n; i ++){
if(now > q[i].id) {
pre = q[i].id;
suf = now;
}else{
pre = now;
suf = q[i].id;
}
pre = pre - getsum(pre);//表示前面有多少个0,多少个还在,包括本身
suf = suf - getsum(suf);
in = suf - pre;
out = n - alre - in;
ans+=min(in,out)+1;
alre ++;
if(alre==n)break;
modify(q[i].id);
if(getsum(n)-getsum(q[i].id)==n-q[i].id)
{
now= bs(0,q[i].id);//边界值问题需要处理一下
}
else
{
now= bs(q[i].id,n);
}
}
cout<<ans<<endl;
}
return 0;
}
线段树代码: 其实我写过一遍类似的poj 2886,当时就是照着别人的代码敲的,还以为自己会了呢,但是发觉理解得还是不够深啊。。。别人的和自己的就是不一样啊。要把别人的学到手!!!
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l,m,rt << 1
#define rson m + 1 , r, rt <<1 | 1
#define havem int m = (l + r) >> 1
#define ls rt << 1
#define rs rt << 1 | 1
#define maxn 100100
int sum[maxn << 2];
void build(int l, int r, int rt){
if(l == r){
sum[rt] = 1;
return ;
}havem;
build(lson); build(rson);
sum[rt] = sum[ls] + sum[rs];
}
void update(int pos, int l, int r, int rt){
if(l == r){
sum[rt] = 0;
return ;
}havem;
if(pos <= m) update(pos,lson);
else update(pos,rson);
sum[rt] = sum[ls] + sum[rs];
}
int query(int L,int R, int l, int r, int rt){
if(L <= l && r <= R){
return sum[rt];
}havem;
int ans = 0;
if(L <= m ) ans = query(L,R,lson);
if(R > m) ans += query(L,R,rson);
return ans;
}
struct Qu{
int id,time;
bool operator < (const Qu& cmp)const{
return time < cmp.time;
}
}q[maxn];
int getpos(int pos, int l, int r, int rt){//去找从1开始的第pos个人,如果pos这个地方就有人,那么就是他了
if(l == r) return l;
havem;
if(pos <= sum[ls])
return getpos(pos,lson);
return getpos(pos - sum[ls],rson);
}
int n;
int main(){
while(~scanf("%d",&n) && n){
build(1,n,1);
for(int i = 1; i <= n; i ++){
scanf("%d",&q[i].time);
q[i].id = i;
}
sort(q + 1, q + 1 + n);
int& mod = sum[1];//
int now = 1;
__int64 ans = 0;
for(int i = 1; i <= n; i ++){
int tmp;
if(now == q[i].id){
ans += 1;
}else if(now < q[i].id){
tmp = query(now + 1,q[i].id,1,n,1);
ans += min(tmp,mod - tmp) + 1;
}else{
tmp = query(q[i].id,now - 1,1,n,1);
ans += min(tmp,mod - tmp) + 1;
}
update(q[i].id,1,n,1);
int Left = query(1,q[i].id,1,n,1);
if( Left < mod ){
//左边小于剩下的人数,说明右边有人,就去右边找
now = getpos(Left + 1,1,n,1);//去找剩下的Left+1个人
}else{
//从后面找第一个1
now = getpos(1,1, n, 1);
}
}
printf("%I64d\n",ans);
}
return 0;
}