51nod oj 1678 lyk与gcd 【容斥定理+打表】

来源:互联网 发布:美国租车软件 编辑:程序博客网 时间:2024/04/28 21:09


传送门:1678


1678 lyk与gcd
基准时间限制: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 31 2 3 4 52 41 3 12 4
Output示例
97

利用容斥定理-----

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

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

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


代码:

#include<cstdio>#include<cmath> #include<vector>#include<cstring>#include<algorithm>using namespace std;#define LL long longvector <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];elsepp[-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];elsepp[-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];elsepp[-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]];elseans+=pp[sta[a][i]];}ans=s-ans;printf("%lld\n",ans);}}return 0;}


0 0
原创粉丝点击