2019CCPC网络赛的一道题目,现场猜到了结论,但本人过于沙雕,试了一下猜想,居然不对,就立刻转身了。

猜想是正确的,是我验证错了....

猜想:

$$ gcd(i^a-j^a,i^b-j^b)=i-j $$

推导结果:

$$ \sum_{d=1}^{N}\mu(d)\cdot d\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{i}(i-j) $$

$$ \lfloor \dfrac{N}{d} \rfloor=k $$

经过推导发现

$$ \sum_{i=1}^{k}\sum_{j=1}^{i}(i-j)=\frac{k^3-k}{6} $$

然后,就只剩下左边的

$$ \mu(d)\cdot d $$

和恒等函数 $Id(n)=n$ 狄利克雷卷积之后得到

$$ \begin{aligned} (\mu(d)\cdot d)*Id(d) & = \sum_{d|n}(\mu(d)\cdot d)\cdot Id(\frac{n}{d})\\ & = \sum_{d|n}\mu(d) \\ & = [n=1] \end{aligned} $$

接下来套杜教筛的公式

$$ g(1)S(n)=\sum\limits_{i=1}^n(f*g)(i)-\sum\limits_{i=2}^ng(i)S(\lfloor\dfrac{n}{i}\rfloor) $$

$$ \begin{aligned} S(n) & = \sum\limits_{i=1}^n [i=1]-\sum\limits_{i=2}^ni\cdot S(\lfloor\dfrac{n}{i}\rfloor)\\ & = 1-\sum\limits_{i=2}^ni\cdot S(\lfloor\dfrac{n}{i}\rfloor) \end{aligned} $$

至此,本题的数学分析过程已经结束,下面是我的AC代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include<unordered_map>
#define ll long long
#define INF 0x3f3f3f3f
#define MAXN 6000100
using namespace std;
unordered_map<long long,long long>w1;
const int mod = 1e9+7;
const int inv6 = 166666668;

int getSum(ll k)
{
    ll k3 = ((k*k%mod)*k)%mod;
    ll res = (k3-k+mod)%mod;
    res = res*inv6%mod;
    return res;
}
int sum[MAXN];
bool vis[MAXN];
int prime[MAXN], mu[MAXN];
void getMobius()
{
    int cnt = 0;
    mu[1] = sum[1] = 1;
    for (int i = 2; i < MAXN; i++)
    {
        if (!vis[i])
        {
            prime[cnt++] = i;
            mu[i] = -1;
        }
        sum[i] = (sum[i-1]+mu[i]*i%mod+mod)%mod;
        for (int j = 0; j < cnt; j++ )
        {
            int k = i*prime[j];
            if(k > MAXN)   break;
            vis[k] = true;
            if (i % prime[j] == 0)
            {
                break;
            }
            mu[k] = -mu[i];
        }
    }
}
unordered_map<int,long long>w;
ll djs(int x)
{
    if(x<MAXN)return sum[x];
    if(w[x])return w[x];
    ll ans=1,td,temp;
    for(int l=2,r;l>=0&&l<=x;l=r+1)
    {
        r=x/(x/l);
        td=(r-l+1);
        td = ((r+l)*td)/2;
        td%=mod;
        temp = td*djs(x/l)%mod;
        ans = (ans-temp+mod)%mod;
    }
    return w[x]=ans;
}
int main()
{
    getMobius();
    int caseN; scanf("%d", &caseN);
    while(caseN--)
    {
        int N, a, b; scanf("%d%d%d", &N, &a, &b);
        ll td, ink, res=0;
        for(int lef = 1, rig; lef <= N; lef=rig+1)
        {
            ink = N/lef;
            rig = N/ink;
            td = (djs(rig)-djs(lef-1)+mod)%mod;
            res = (res+getSum(ink)*td%mod)%mod;
        }
        printf("%lld\n", res);
    }
    return 0;
}

感想

知道我的猜想是正确的之后,吃完晚饭就开始做这道题,好久好久终于改好了

期间,简单打表会RE,就转了杜教筛

开始打表空间用的太多MLE,太少TLE

最后找到一个神奇的6e6,不会MLE也不会TLE,结果WA了

想了一会儿,又瞄了一眼答案,好像我搞了半天的东西不太对哦

只是推导结果不一样而已

顿生绝望,算了,老子明天再看,这种套模板的题能有多难?

早上睡不着,突然想到这道题目打表范围开大以后应该要mod的

一开始我只开了1e6,没有mod

于是改了一下,居然AC了!哇,第一道杜教筛题目,欢天喜地!


licoded
1 声望0 粉丝