LA 7243 Frogs [容斥定理]

来源:互联网 发布:jquery封装json数据 编辑:程序博客网 时间:2024/05/16 04:56

Regionals 2015 :: Asia - Shenyang

Source

LA 7243
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=692&page=show_problem&problem=5255

Description

Input N, M
N : 青蛙个数
M : 圈的长度
Input A0, A1, … , AN-1
i青蛙从0开始 每次跳 Ai 格
超过了M. 就mod M
求这些被青蛙所跳过的格子的数之和

Limits

N < 1e4
M < 1e9
Ai < 1e9

in.txt

32 129 103 6022 33 669 9681 40 48 32 64 16 96 42 72

out.txt

4211701872

Sample Explanation

N=2 M=12
A0 = 9 A1 = 10

0号青蛙
0 -> 9 -> (9+9) mod 12 = 6 -> (6+9) mod 12 = 3 -> (3+9) mod 12 = 0
经过 0,9,6,3

1号青蛙
10->8->6->4->2->0
总共经过
0 2 3 4 6 8 9 10
S = 42

Guess

经过的都是gcd(Ai, M)的倍数

Proof

设经过的点为b
ax = b mod m
ax - b = my
ax - my = b
当且仅当 b = k gcd(a, m)

Bézout’s identity
https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity

Algorithm

找到m的所有因子,保存在 factors 数组
对于factors中的每一个元素 x
如果m mod x = 0,则x的所有倍数都需要加到ans里面去
使用function sum来实现
但是会出现重复
对于每个元素
用两个数组记录状态
Used 表明这个元素是否为 gcd(ai, m)
Nums 表明这个元素使用的次数
对于6
Used = true
初始阶段 Nums = 0
执行到元素 2 时,6的倍数被加了1遍 Nums = 1
执行到元素 3 时,6的倍数又被加了1遍 Nums = 2
这样到 6的时候Ans就需要减去一次 6的倍数,同时修改12
对于12
2的时候 Nums++
3的时候 Nums++
到6的时候 Nums- -
所有到12时 Nums == Used 略去了

Code

#include <algorithm>#include <cmath>#include <cstdio>#include <iostream>#include <vector>#include <cstring>using namespace std;typedef long long ll;const ll MAXM = 1e9 + 9;const ll MAXN = 1e4 + 9;int a[MAXN];bool b[MAXM];int m;ll sum(ll a0, ll an, ll d) {  return (a0 + an) * ((an - a0) / d + 1) / 2 - m;}void solve() {  memset(a, 0, sizeof(a));  int n;  scanf("%d%d", &n, &m);  for (ll i = 0; i < n; i++) {    scanf("%d", &a[i]);  }  vector<ll> factors;  for (ll i = 1; i <= sqrt(m); i++) {    if (m % i == 0) {      factors.push_back(i);      if (i * i != m)      factors.push_back(m / i);    }  }  sort(factors.begin(), factors.end());  factors.pop_back();  ll l = factors.size();  vector<ll> nums(l, 0);  vector<bool> used(l, 0);  for (ll i = 0; i < n; i++) {    ll it = lower_bound(factors.begin(), factors.end(), __gcd(a[i], m)) - factors.begin();    for (ll j = it; j < l; j++) {      if (factors[j] % factors[it] == 0) {        used[j] = true;      }    }  }  long long ans = 0;  for (ll i = 0; i < l; i++) {    ll t = used[i] - nums[i];    if (used[i]) {      ans += t * sum(factors[i], m / factors[i] * factors[i], factors[i]);      for (ll j = i + 1; j < l; j++) {        if (factors[j] % factors[i] == 0) {          nums[j] += t;        }      }    }  }  cout << ans << endl;}int main() { // freopen("in.txt", "r", stdin);  int t;  scanf("%d", &t);  for (int i = 1; i <= t; i++) {    printf("Case #%d: ", i);    solve();  }}
0 0
原创粉丝点击