• 【莫比乌斯反演】10.30破译密码


    初涉的话先留坑吧

    题目大意

    $sum_{i_1}^{a_1}sum_{i_2}^{a_2}cdotssum_{i_m}^{a_m}(i_1,i_2,cdots,i_m)$

    $a_i<=1e6,2=<m<=10$

    题目分析

    首先寄存两篇比较好的博客:

    1.铃悬的数学小讲堂——狄利克雷卷积与莫比乌斯反演

    2.[学习笔记]莫比乌斯反演常见模型

    这个问题可以推广至一类模型:$sum_{i=1}^nsum_{j=1}^mf[gcd(i,j)]$.

    该模型的推论是$原式=sum_{u=1}^{min(n,m)}lfloorfrac{n}{u} floorlfloorfrac{m}{u} floorsum_{d|u}f[d]mu(frac{u}{d})$

    注意到在本题中$f=id$,那么也就是说$原式=sum_{u=1}^{min(n,m)}lfloorfrac{n}{u} floorlfloorfrac{m}{u} floor varphi(u)$.

    因此先一遍线性筛求$varphi$的前缀和,再数论分块做$lfloorfrac{n}{u} floor$这一部分。

    本题对模型的转化还不算太深(算是比较裸的反演)

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 13;
     4 const int MO = 1e9+7;
     5 const int TOP = 1000000;
     6 const int maxPri = 80035;
     7 const int maxNum = 1000035;
     8 
     9 int T,n,mn,a[maxn],pr[maxPri];
    10 ll phi[maxNum],ans,tmp;
    11 bool vis[maxNum];
    12 
    13 int read()
    14 {
    15     char ch = getchar();
    16     int num = 0;
    17     bool fl = 0;
    18     for (; !isdigit(ch); ch=getchar())
    19         if (ch=='-') fl = 1;
    20     for (; isdigit(ch); ch=getchar())
    21         num = (num<<1)+(num<<3)+ch-48;
    22     if (fl) num = -num;
    23     return num;
    24 }
    25 void init()
    26 {
    27     phi[1] = 1;
    28     for (int i=2; i<=TOP; i++)
    29     {
    30         if (!vis[i]) pr[++pr[0]] = i, phi[i] = i-1;
    31         for (int j=1; (j<=pr[0])&&(pr[j]*i<=TOP); j++)
    32         {
    33             vis[pr[j]*i] = 1, phi[pr[j]*i] = phi[i]*pr[j];
    34             if (i%pr[j]==0) break;
    35             phi[pr[j]*i] = phi[i]*(pr[j]-1);
    36         }
    37     }
    38     for (int i=2; i<=TOP; i++) phi[i] = (phi[i]+phi[i-1])%MO;
    39 }
    40 int main()
    41 {
    42     freopen("gcd.in","r",stdin);
    43     freopen("gcd.out","w",stdout);
    44     T = read(), init();
    45     while (T--)
    46     {
    47         n = read(), ans = 0, mn = 0x3f3f3f3f;
    48         for (int i=1; i<=n; i++)
    49             a[i] = read(), mn = mn>a[i]?a[i]:mn;
    50         for (int i=1, j=0; i<=mn; i=j+1)
    51         {
    52             j = mn, tmp = 1;
    53             for (int k=1; k<=n; k++) j = std::min(j, a[k]/(a[k]/i));
    54             for (int k=1; k<=n; k++) tmp = tmp*(a[k]/i)%MO;
    55             ans = (ans+(phi[j]-phi[i-1]+MO)*tmp%MO)%MO;
    56         }
    57         printf("%lld
    ",ans);
    58     }
    59     return 0;
    60 }

    END

  • 相关阅读:
    2021年4月27日 团队冲刺阶段01
    2021年4月26日
    2021年4月25日
    2021年4月24日
    2021年4月23日
    2021年4月22日
    2021年4月21日
    神奇的数列之“Last Defence ”
    经典圆交面积求解之“Intersection ”
    计蒜客第六场
  • 原文地址:https://www.cnblogs.com/antiquality/p/9892267.html
Copyright © 2020-2023  润新知