#include <bits/stdc++.h>
using namespace std;
int m,n;
int E;
const int maxn = 1e5;
int a[maxn],factor[maxn],vis[maxn],num[maxn]; /*vis:应该访问的次数;num:当前访问的次数*/
void Init() {
E = 0;
memset(factor,0,sizeof(factor));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
}
int gcd(int a, int b) {
return b == 0? a: gcd (b,a%b);
}
void GetFactor() { //因数分解
for(int i = 1 ; i * i <= m ; i++) {
if(m % i == 0) {
factor[E++] = i;
if(i * i != m) {
factor[E++] = m/i;
}
}
}
sort(factor,factor+E);
}
void GetVisit() { //判断factor会不会出现访问
for(int i = 0 ; i < n ; i++) {
int x = gcd(a[i],m);//当前能访问到的位置的最小下标
for(int j = 0 ; j < E ; j++) {
if(factor[j] % x == 0 && factor[j] != m/*注意把下标为m的点排除*/) {
vis[j] = 1;
}
}
}
}
long long GetValue() {
long long ans = 0;
for(int i = 0 ; i < E ; i++) {
if(vis[i] != num[i]) { // 如果当前计算次数和应该计算的次数相等factor[i]就不会出现在求和里
long long t = (m)/factor[i];
ans += (1+t)*t/2 * factor[i] * (vis[i] - num[i]);
// 等差数列求一下和然后乘上 (应该应该访问的次数)与(当前访问的次数)的差 容斥一下
for(int j = i+1 ; j < E ; j++) { // 把能整除当前facrot的当前访问次数也更新
if(factor[j] % factor[i] == 0)
num[j] += (vis[i] - num[i]);
}
}
}
return ans;
}
int main() {
int T;
cin >> T;
int kase = 1;
while(T--) {
Init();
cin >> n >> m;
for(int i = 0 ; i < n ; i++) {
cin >> a[i];
}
GetFactor();
GetVisit();
printf("Case #%d: %lld\n",kase++,GetValue());
}
return 0;
}
HDU - 5514(容斥)
最新推荐文章于 2019-08-03 18:48:00 发布