传送门:1678
基准时间限制:2 秒 空间限制:131072 KB 分值: 80
难度:5级算法题
这天,lyk又和gcd杠上了。
它拥有一个n个数的数列,它想实现两种操作。
1:将
改为b。
2:给定一个数i,求所有
时的
的总和。
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
利用容斥定理-----
先将每个数加到它的约数里----
然后每次利用容斥定理求出和 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;
}