題意:給你n種步長,無限走一個圈,圈長m,位置標號從0到m−1,求至少被經過一次的位置之和。
思路:來自:點擊打開鏈接
大致思路就是用兩個數組記錄每一個因子該算幾遍和已經算了幾遍了。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN = 40010;
int factor[MAXN], step[MAXN], bk[MAXN], num[MAXN];
int main()
{
int T, n, m;
cin >> T;
for(int kase = 1; kase <= T; kase++)
{
int cnt = 0;
memset(bk, 0, sizeof(bk));
memset(num, 0, sizeof(num));
scanf("%d %d", &n, &m);
for(int i = 1; i * i <= m; i++)
if(m % i == 0)
{
factor[cnt++] = i;
if(m / i != i)
factor[cnt++] = m / i;
}
sort(factor, factor + cnt);
cnt--;//把m去除
for(int i = 1; i <= n; i++)
{
scanf("%d", step + i);
step[i] = __gcd(step[i], m);
for(int j = 0; j < cnt; j++)
{
if(factor[j] % step[i] == 0)
bk[j] = 1;
}
}
ll ans = 0, tmp;
for(int i = 0; i < cnt; i++)
{
if(bk[i] == num[i]) continue;
tmp = (m - 1) / factor[i];//注意是用 m - 1 除
ans += 1ll * tmp * (tmp + 1) / 2 * factor[i] * (bk[i] - num[i]);
tmp = bk[i] - num[i];
for(int j = i; j < cnt; j++)
{
if(factor[j] % factor[i] == 0)
num[j] += tmp;
}
}
printf("Case #%d: %lld\n", kase, ans);
}
return 0;
}