poj2886 約瑟夫環,樹狀陣列

2021-08-23 14:11:23 字數 1673 閱讀 8542

n個人圍成圈,每個人手上有乙個數字,最開始k跳出圈,如果k手上的數num是正數,則向左num個人出圈,負數就向右,直到所有人都出圈,得分最高的是第(1-n中因子數最多的數)次跳出的人

首先處理1-n中因子最多的數,有個名詞叫反素數,不管他這裡直接打表

#include #include #include #include using namespace std;

const int mx = 6e5 + 5;

int cnt[mx], anti_prim[mx], num[mx], tot = 0;

int main() }}

int max_num = 0;

for (int i = 1; i <= 600000; i++)

}for (int i = 1; i <= tot; i++)

for (int i = 1; i <= tot; i++)

return 0;

}

接著是處理跳出次序問題,用樹狀陣列記錄每個位置的人是否已經跳出,剛開始看到題解說二分我以為是把人按1-n排列,第k個人跳出就從k開始向左或向右進行二分出下乙個跳出的人的位置,但是這樣會有問題,比如第k個人手上是5,那麼應該向右二分出5個人,但是有可能右邊不足五個人需要繞回到左邊,所以這樣是行不通的

正確的做法是把人按1-n排列,然後每次有人跳出就通過公式計算出下乙個人是從1-n中還在圈內的第幾個,這樣就可以二分1-n了

#include #include #include #include using namespace std;

const int mx = 5e5 + 5;

int anti_prim = ;

int num = ;

int n, k, c[mx];

struct node stu[mx];

int lowbit(int x)

void add(int x, int val)

}int sum(int x)

return ans;

}int bit_search(int x)

return left;

}int main()

int pos = lower_bound(anti_prim, anti_prim + 36, n) - anti_prim;

if (anti_prim[pos] > n) pos--;

int now = k, next = k, remaining = n - 1, cnt = 1, ans;

add(k, -1);

while (true)

int m = stu[now].value;

if (m > 0) next = (next - 1 + m) % remaining;

else next = ((next + m) % remaining + remaining) % remaining;

if (next == 0) next = remaining;

remaining--; cnt++;

now = bit_search(next);

add(now, -1);

}printf("%s %d\n", stu[ans].name, num[pos]);

}return 0;

}

poj 2886 線段樹 單點更新

題意 n個小孩圍成一圈,玩約瑟夫環,每個小孩有一張卡片上面是數字a,正數代表右手邊第a個小孩出隊,負數表示左手邊,遊戲從第k個小孩開始,遊戲直到所有小孩出隊為止,第p個出隊小孩得到f p 分數,f p 為p的因子數 題解 這裡引入反素數的概念不清楚可以看 每次詢問只要從第乙個出隊的執行到當前給出的n...

poj2886 線段樹單點更新)

到1號節點的距離為s的點,則該點的相對節點1的編號為 s n n 1,另外此題要打表求某個數的因子個數 反素數就是 對 x來說約束個數 g x 如果 對於 i includeusing namespace std const int maxn 500002 反素數及因子個數打表 int ap 40 ...

poj2886 線段樹單點修改 反素數(喵?)

n個熊孩子每個人有個數字a i 首先k號熊孩子出圈,然後第k a i 個熊孩子出圈,乙個環,可以繞很多圈,如果a i 為正則順時針數,反之逆時針,相當於乙個變體的約瑟夫遊戲,第i個出圈的熊孩子,有f i 的得分,f i 為i的因子個數 分為兩個部分 線段樹模擬約瑟夫遊戲 尋找1到n範圍內因數數量最多...