2019 hdu多校round1 1011 Function(数论+线性预处理)

题目传送门

简单题意

\sum_{i = 1}^{n} gcd(\lfloor \sqrt[3]{i}\rfloor,i)\mod998244353,n<=1e21

算法

先分块,有\sum_{i = 1}^{\lfloor\sqrt[3]{n}\rfloor}\sum_{j = i^3}^{min(n,(i+1)^3+1)}gcd(i,j)

令函数f(i,j)=\sum_{x=1}^{m}gcd(i,x)\Rightarrow f(i,j) = \lfloor\frac{j}{i}\rfloor f(i,i)+f(i,j\%i)

f(i,i)=\sum_{d|i}d\phi(\frac{i}{d}),f(i,j)=\sum_{d|i}\frac{j}{d}\phi(d)

\sum_{j=i^3}^{(i+1)^3+1}gcd(i,j),通过差分有f(i,(i+1)^3+1)-f(i,i^3)=3*(i+1)f(i,i)+gcd(i,i^3)=3*(i+1)f(i,i)+i,显然f(i,i)通过线性欧拉筛可以O(n+\sqrt{n}\log{n})预处理.

所以显然只需要考虑上界为n时的情况,O(\sqrt{n})的跑一边f(i,n)即可。

这题卡常很严,所以离线查询(__int128长见识了),整体复杂度为O(n+(t+logn)*\sqrt{n})

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e7 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
int lcm(int a,int b){return a / gcd(a,b) * b;}
ll fpow(ll a,ll b)
{
    ll res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
void read(__int128 &x) {
    static char ch;static bool neg;
    for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
    for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
    x=neg?-x:x;
}
int phi[N],prime[N],cnt;
bool isprime[N];
ll f[N];
void get_phi()
{
   phi[1] = 1;
   for(int i = 2;i < N;++i){
       if(!isprime[i]){
             prime[++cnt] = i;
             phi[i] = i - 1;
        }
       for(int j = 1;j <= cnt && i * prime[j] < N;++j){
          isprime[i * prime[j]] = 1;
          if(i % prime[j] == 0){
             phi[i * prime[j]] = phi[i] * prime[j];
             break;
          }
          else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
       }
   }
   for(int i = 1;i * i < N;++i){
       int p = i * i;
       for(int j = i * i;j < N;j += i){
           f[j] = (f[j] + i * phi[j / i]) % mod;
           if(p < j) f[j] = (f[j] + (j / i) * phi[i]) % mod;
       }
   }
}
struct node{
    __int128 n;
    int id;
}a[20];
bool cmp(node a,node b)
{
    return a.n < b.n;
}
//ll n;
ll ans[20],pos[20];
int main()
{
    //freopen("in.txt","r",stdin);
    get_phi();
    int t;
    scanf("%d",&t);
    for(int i = 0;i < t;++i){
        read(a[i].n);
        a[i].id = i;
        //scanf("%lld",&n);
    }
    sort(a,a + t,cmp);
    for(__int128 i = 1,cnt = 0;i * i * i < a[t - 1].n;++i){
        if((i + 1) * (i + 1) * (i + 1) > a[cnt].n){
            if(cnt == t - 1){
                pos[cnt] = i;
                break;
            }
            while((i + 1) * (i + 1) * (i + 1) > a[cnt].n){
                pos[cnt] = i;
                cnt++;
                ans[cnt] = ans[cnt - 1];
            }

        }
        ans[cnt] = (ans[cnt] + 3LL * (i + 1) * f[i] + i) % mod;
        if((i + 1) * (i + 1) * (i + 1) == a[cnt].n) ans[cnt] = (ans[cnt] + i + 1) % mod,pos[cnt] = 0;
    }
    for(int jq = 0;jq < t;++jq){
        if(pos[jq]){
            ll rnt = a[jq].n % pos[jq],ret = a[jq].n / pos[jq] % mod;
            for(ll i = 1;i * i <= pos[jq];++i){
                ll l = pos[jq] / i;
                if(pos[jq] % i == 0){
                    ans[jq] = (ans[jq] + (rnt / i) * phi[i]) % mod;
                    if(i * i < pos[jq]) ans[jq] = (ans[jq] + (rnt / l) * phi[l]) % mod;
                }
                i = pos[jq] / l;
            }
            ans[jq] = (ans[jq] + (ret - (pos[jq] * pos[jq])) % mod * f[pos[jq]] % mod + pos[jq] + mod) % mod;
        }
    }
    for(int i = 0;i < t;++i){
        for(int j = 0;j < t;++j)
            if(a[j].id == i)printf("%lld\n",ans[j]);
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值