Codeforces 819 D. Mister B and Astronomers 數論
阿新 • • 發佈:2019-02-01
題意:
有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... 將這些人放在一個環中,可以發現兩兩之間是沒有交,那麼怎麼樣可以更簡單的計算答案,把環分成
g ,環長就是cd(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;
}