51nod lyk与gcd

1678 lyk与gcd

基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

这天,lyk又和gcd杠上了。
它拥有一个n个数的数列,它想实现两种操作。

1:将  ai 改为b。
2:给定一个数i,求所有 gcd(i,j)=1 时的  aj  的总和。

Input

第一行两个数n,Q(1<=n,Q<=100000)。
接下来一行n个数表示ai(1<=ai<=10^4)。
接下来Q行,每行先读入一个数A(1<=A<=2)。
若A=1,表示第一种操作,紧接着两个数i和b。(1<=i<=n,1<=b<=10^4)。
若B=2,表示第二种操作,紧接着一个数i。(1<=i<=n)。

Output

对于每个询问输出一行表示答案。

Input示例

5 3
1 2 3 4 5
2 4
1 3 1
2 4

Output示例

9
7思路 

考虑辅助数组f[i]表示所有下标为i的倍数的a数组的总和。

例如有5个数,那么f[1]=a[1]+a[2]+a[3]+a[4]+a[5],f[2]=a[2]+a[4],f[3]=a[3],f[4]=a[4],f[5]=a[5]。

对于每一个修改操作,我们只需要求出i的所有因数,然后将下标为它的因数的f数组中修改值即可。

对于所有询问操作,求出i的所有因数p1,p2,p3...之后答案即为Σu[pi]*f[pi]。

其中u为mobius函数。

总复杂度为所有操作中i的因数个数总和。

利用容斥定理----

先将每个数加到它的约数里---

然后每次利用容斥定理求出和 i 不互素的数的和---

总和-求的和就为所要的解


#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
vector <int > sta[200100];
int shu[220000];
int ou[100],ll;
int qu[200100],kkp;
LL pp[200100];
void init(int n)
{
    int su[200100],kp=0;
    bool fa[200100];
    memset(fa,true,sizeof(fa));
    for (int i=2;i<=n;i++)
    {
        if (fa[i])
        {
            su[kp++]=i;
            if (i<=sqrt(n))
            for (int j=i*i;j<=n;j+=i)
                fa[j]=false;
        }
    }
    for (int i=2;i<=n;i++)
    {
        int ll=0;
        int kk=i;
        for (int j=0;su[j]*su[j]<=kk;j++)
        {
            if (kk%su[j]==0)
                ou[ll++]=su[j];
            while (kk%su[j]==0)
                kk/=su[j];
        }
        if (kk>1)
            ou[ll++]=kk;
        kkp=0;
        qu[kkp++]=-1;
        for (int j=0;j<ll;j++)
        {
            kk=kkp;
            for (int k=0;k<kk;k++)
                qu[kkp++]=qu[k]*ou[j]*-1;
        }
        for (int j=1;j<kkp;j++)
            sta[i].push_back(qu[j]);
    }
}
int main()
{
    int n,k;
    /*freopen("In.txt","r",stdin);
    freopen("wo.txt","w",stdout);*/
    scanf("%d%d",&n,&k);
    init(n);
    LL s=0,ans;
    memset(pp,0,sizeof(pp));
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&shu[i]);
        for (int j=0;j<sta[i].size();j++)
        {
            if (sta[i][j]>0)
                pp[sta[i][j]]+=shu[i];
            else
                pp[-sta[i][j]]+=shu[i];
        }
        s+=shu[i];
    }
    int a,b,c;
    while (k--)
    {
        scanf("%d",&c);
        if (c==1)
        {
            scanf("%d%d",&a,&b);
            for (int j=0;j<sta[a].size();j++)
            {
                if (sta[a][j]>0)
                    pp[sta[a][j]]-=shu[a];
                else
                    pp[-sta[a][j]]-=shu[a];
            }
            s-=shu[a];
            shu[a]=b;
            for (int j=0;j<sta[a].size();j++)
            {
                if (sta[a][j]>0)
                    pp[sta[a][j]]+=shu[a];
                else
                    pp[-sta[a][j]]+=shu[a];
            }
            s+=shu[a];
        }
        else
        {
            scanf("%d",&a);
            if (a==1)
            {
                printf("%lld\n",s);
                continue;
            }
            ans=0;
            for (int i=0;i<sta[a].size();i++)
            {
                if (sta[a][i]<0)
                    ans-=pp[-sta[a][i]];
                else
                    ans+=pp[sta[a][i]];
            }
            ans=s-ans;
            printf("%lld\n",ans);
        }
    }
    return 0;
}  

这道题是我复制借鉴的http://blog.csdn.net/leibniz_zhang/article/details/52318715这位大佬的 = =

				
时间: 2024-10-13 17:39:22

51nod lyk与gcd的相关文章

51nod 1678 lyk与gcd

这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai 改为b.2:给定一个数i,求所有 gcd(i,j)=1 时的  aj  的总和. Input 第一行两个数n,Q(1<=n,Q<=100000). 接下来一行n个数表示ai(1<=ai<=10^4). 接下来Q行,每行先读入一个数A(1<=A<=2). 若A=1,表示第一种操作,紧接着两个数i和b.(1<=i<=n,1<=b<=10^4). 若B=2,表示第

51 Nod 1678 lyk与gcd

1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai 改为b.2:给定一个数i,求所有 gcd(i,j)=1 时的  aj  的总和. Input 第一行两个数n,Q(1<=n,Q<=100000). 接下来一行n个数表示ai(1<=ai<=10^4). 接下来Q行,每行先读入一个数A(1<=A<=2). 若A=1,表示第一种

1678 lyk与gcd

1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将  ai 改为b.2:给定一个数i,求所有 gcd(i,j)=1 时的  aj  的总和. Input 第一行两个数n,Q(1<=n,Q<=100000). 接下来一行n个数表示ai(1<=ai<=10^4). 接下来Q行,每行先读入一个数A(1<=A<=2). 若A=1,表示第一种操作,紧接着两个数i和b.(1&

51nod算法马拉松15

智力彻底没有了...看来再也拿不到奖金了QAQ... A B君的游戏 因为数据是9B1L,所以我们可以hash试一下数据... #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) using n

【51nod1220】约数之和

题目 d(k)表示k的所有约数的和.d(6) = 1 + 2 + 3 + 6 = 12. 定义S(N) = ∑1<=i<=N ∑1<=j<=N d(i*j). 例如:S(3) = d(1) + d(2) + d(3) + d(2) + d(4) + d(6) + d(3) + d(6) + d(9) = 59,S(1000) = 563576517282. 给出正整数N,求S(N),由于结果可能会很大,输出Mod 1000000007(10^9 + 7)的结果. 分析 分开处理每个

1011 最大公约数GCD(51NOD基础题)

1011 最大公约数GCD(51NOD基础题) 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 输入2个正整数A,B,求A与B的最大公约数. Input 2个数A,B,中间用空格隔开.(1<= A,B <= 10^9) Output 输出A与B的最大公约数. Input示例 30 105 Output示例 15 /* <1> 循环实现 辗转相除法 <2> 递归实现 辗转相除法 */ #include <cstdio> #defi

51nod 1011最大公约数GCD

1011 最大公约数GCD 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 输入2个正整数A,B,求A与B的最大公约数. Input 2个数A,B,中间用空格隔开.(1<= A,B <= 10^9) Output 输出A与B的最大公约数. Input示例 30 105 Output示例 15百度~辗转相除法,嗯,wrong了4遍(逃) #include<stdio.h> int gcd(int a,int b) { int t; if(

51nod 1594 Gcd and Phi 反演

OTZ 又被吊打了...我当初学的都去哪了??? 思路:反演套路? 提交:\(1\)次 题解: 求\(\sum_{i=1}^{n}\sum_{j=1}^{n}\varphi(gcd(\varphi(i),\varphi(j)))\) 设\(c[i]=\sum_{j=1}^n[\varphi(j)==i]\) 有: \(\sum_{i=1}^{n}\sum_{j=1}^{n}\varphi(gcd(i,j))*c[i]*c[j]\) 欧拉反演一下,把\(gcd\)扔出来 \(\sum_{i=1}^

51nod 1594 Gcd and Phi(莫比乌斯反演)

题目链接 传送门 思路 如果这题是这样的: \[ F(n)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\phi(gcd(i,j)) \] 那么我们可能会想到下面方法进行反演: \[ \begin{aligned} F(n)=&\sum\limits_{k=1}^{n}\phi(k)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(i,j)=k]&\=&\sum\limits_{k=1}^{n}\p