Каосар і підрахунок#12328

Каосар і підрахунок (Розбір)

Автор проблеми:

AlKaosar Hussain

Підготовлено:

Hasan Saleh (MathModel)

Редаговано:

Hasan Saleh (MathModel)

Рішення

Ми підраховуємо трійки (a,b,c) з 1\le a,b,c\le n, які є трьома послідовними членами арифметичної прогресії, парно різними і задовольняють \gcd(a,b,c)=1.

Оскільки (a,b,c) є послідовними в арифметичній прогресії, існують цілі числа і d\ge1, такі що

(a,b,c)=(x-d,x,x+d).

Обмеження вказують на те, що

d+1\le x\le n-d, \qquad d\le \frac{n-1}{2}.

Зверніть увагу, що

\gcd(x-d,x,x+d)=\gcd(x,d),

оскільки \gcd(x-d,x)=\gcd(x,d) і \gcd(x,x+d)=\gcd(x,d). Отже, умова \gcd(a,b,c)=1 еквівалентна \gcd(x,d)=1.

Для фіксованого нехай A=n-2d. Тоді змінюється по послідовним цілим числам, і кількість дійсних центрів дорівнює

\sum_{k\mid d}\mu(k)\left\lfloor\frac{A}{k}\right\rfloor,

за допомогою обернення Мебіуса. Пряме підсумовування по всіх занадто повільне, тому ми використовуємо префіксні суми функції Мебіуса. Нехай

M(t)=\sum_{i=1}^{t}\mu(i).

Ми ітеруємо в блоках, де обидва

A=\left\lfloor\frac{n}{d}\right\rfloor \quad\text{та}\quad J=\left\lfloor\frac{n-1}{2d}\right\rfloor

залишаються постійними. Для такого блоку d\in[l,r] загальний внесок дорівнює

\big(JA-J(J+1)\big)\cdot\big(M(r)-M(l-1)\big).

Сумування цих внесків по всіх блоках дає кількість пар з дійсними x-d,x,x+d і \gcd(x,d)=1.

Нарешті, кожна дійсна пара генерує дві впорядковані трійки,

(x-d,x,x+d)\quad\text{та}\quad(x+d,x,x-d),

тому ми множимо результат на .

Функція Мебіуса та її префіксні суми попередньо обчислюються до 10^6 за часу. Кожен тестовий випадок обробляється за O(\sqrt{n}), що легко задовольняє обмеження.

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N=1000000;

int mu[N+1],pm[N+1];
int p[N],pc;
bool c[N+1];

inline int M(int x){
    if(x<=0)return 0;
    return pm[x];
}

void precalc(){
    mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!c[i]){
            p[pc++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<pc;j++){
            int x=p[j];
            if(i*x>N)break;
            c[i*x]=1;
            if(i%x==0){
                mu[i*x]=0;
                break;
            }
            mu[i*x]=-mu[i];
        }
    }
    for(int i=1;i<=N;i++)pm[i]=pm[i-1]+mu[i];
}

void solve(){
    int n;cin>>n;
    int lim=(n-1)/2;
    int ans=0;
    for(int l=1;l<=lim;){
        int A=n/l;
        int J=(n-1)/(2*l);
        int r=min({n/A,(n-1)/(2*J),lim});
        ans+=(J*A-J*(J+1))*(M(r)-M(l-1));
        l=r+1;
    }
    cout<<(ans*2)<<"\n";
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    precalc();
    int t=1;cin>>t;
    while(t--)solve();
}