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
3
2 12
9 10
3 60
22 33 66
9 96
81 40 48 32 64 16 96 42 72
#out.txt
42
1170
1872
#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ézout’s_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();
}
}
5682

被折叠的 条评论
为什么被折叠?



