Codeforces 819 D. Mister B and Astronomers 数论

来源:互联网 发布:程序员考核表 编辑:程序博客网 时间:2024/06/02 04:45
题意:

有T个石子,n个人,每个人轮流取石子,一颗石子只能取一次,求每个人能取到多少石子。
假设i-1号取的位置为pos,那么i号取的位置就是(pos+ai)modT,如果当前位置的石子已经被取走,这个人的所取石子数量不增加,i+1取的位置为(pos+ai+ai+1)modT

算法:
  • S=ni=1ai
  • sti=ni=2ai,为每个人第一次取得位置,不考虑那些第一次就取不到的人。那么每个人可以取到的就是(sti+S)modT(sti+2S)modT...

将这些人放在一个环中,可以发现两两之间是没有交,那么怎么样可以更简单的计算答案,把环分成gcd(S,T),环长就是Tgcd(S,T),一个人可以取的石子就是与下一个人在所在环上距离。证明显然,其实是不会,感性愉悦下就好。

代码:
#include <cstdio>#include <map>#include <string.h>#include <algorithm>#include <cmath>using namespace std;int rd() {    int x = 0; char c = getchar();    while (c > '9' || c < '0') c = getchar();    while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();    return x;}void wt(int x) {    if (x >= 10) wt(x / 10);    putchar(x % 10 + 48);}void exgcd(int a, int b, int &x, int &y) {    if (!b) { x = 1, y = 0; return; }    exgcd(b, a % b, x, y);    int t = x;    x = y, y = t - a / b * y;}const int N = 2e5 + 10;struct Pt{    int bel, pos, id;    Pt(int a = 0, int b = 0, int c = 0) : bel(a), pos(b), id(c) {}    bool operator < (const Pt &t) const {        return bel < t.bel || (bel == t.bel && pos < t.pos);    }} c[N];map <int, int> mp;int T, n, a[N], ans[N], S, cnt;int main() {    T = rd(), n = rd();    for (int i = 1; i <= n; i ++) a[i] = rd(), S = (S + a[i]) % T;    int t = -a[1];    for (int i = 1; i <= n; i ++) {        t = (t + a[i]) % T;        if (!mp[t]) mp[t] = i;    }    int g = __gcd(S, T), len = T / g, step = S / g, inv, y;    //printf("%d %d %d\n", S, T, g);    t = -a[1], exgcd(step, len, inv, y);    inv = (inv + len) % len;    for (int i = 1; i <= n; i ++) {        t = (t + a[i]) % T;        if (mp[t] == i) c[++cnt] = Pt(t % g, 1ll * (t / g) * inv % len, i);    }    sort(c + 1, c + cnt + 1);    for (int i = 1; i <= cnt; i ++) {        int j = i;        while (j < cnt && c[j + 1].bel == c[i].bel) j ++;        //printf("%d\n", j);        for (int k = i; k < j; k ++) ans[c[k].id] += c[k + 1].pos - c[k].pos;        ans[c[j].id] += c[i].pos + len - c[j].pos;        i = j;    }    for (int i = 1; i <= n; i ++) wt(ans[i]), putchar(32); puts("");    return 0;}
原创粉丝点击