UCF Local Programming Contest 2017—— Rotating Cards(樹狀數組+思維)

題目鏈接:https://nanti.jisuanke.com/t/44825

此題需要每次去掉top位置的紙牌後實時更新前綴和,於是可以考慮樹狀數組,樹狀數組的時間複雜度是log級別。

思路:設剛去掉的紙牌原來的位序是pre,現在的位序是now,剩餘紙牌的數字和是n,比如從top到bottom依次爲3 5 1 4 2 ;設pre=3,now=5,分別對應的是1和2號紙牌; 接下來要去掉2號牌(1號已經去掉),需要比較兩個區間的和,一個是(pre,now)開區間,設和爲x,另一個區間不需要指出,只需要直接求出其和n-x;所以取min(n-x,x);其中x=sum[now-1]-sum[pre-1];當然上述情況爲now>pre的情況,now<pre的情況同理可以推理出。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <cstdio>
#include <string>
#include <stack>
#include <set>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
typedef long long ll;
ll id[100010],pre;
ll num[100010],c;
ll d[100010];
ll lowbit(ll pos){
    return pos&(-pos);
}
void add(ll pos,ll val){
    while(pos<=c){
        d[pos]+=val;
        pos+=lowbit(pos);
    }
    return ;
}
ll getsum(ll pos){
    ll sum=0;
    while(pos>0){
        sum+=d[pos];
        pos-=lowbit(pos);
    }
    return sum;
}
int main()
{
    IOS;
    ll t;
    cin>>t;
    while(t--){
        memset(id,0,sizeof(id));
        memset(num,0,sizeof(num));
        memset(d,0,sizeof(d));
        cin>>c;
        for(int i=1;i<=c;i++){
            cin>>num[i];
            add(i,num[i]);
            id[num[i]]=i;//建立索引
        }
        ll n=c*(c+1)/2;
        ll cost=0;
        pre=0;
        for(int i=1;i<=c;i++){
            ll p1=getsum(id[i]-1),p2=getsum(pre-1);//先處理兩個前綴和
            //接下來分兩種情況取最小值
            if(id[i]>pre){
                cost+=min(n-(p1-p2),p1-p2);
                add(id[i],-i);
                n-=i;
                pre=id[i];
            }
            else{
                cost+=min(n-(p2-p1),p2-p1);
                add(id[i],-i);
                n-=i;
                pre=id[i];
            }
        }
        cout<<cost<<endl;
    }
    getchar();
    getchar();
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章