hdoj4407题解
题目描述:1,2,3.....n排一行(1<=n<=400000),接下来有m(1<=m<=1000)操作,操作分为两种,一种是查询,一种是改值。
查询:输入x,y,p,求第x个数到第y个数之间与p互质的数的和
改值:输入x,c,将第x个数的值改为c
这题用到容斥原理,先认为第x到第y个数是连续的,对于连续的数求与p互质的数的和可以用第x个数到第y个数的和减去与p有公约数的和。
对于改值,用个数组记录下来要修改的数的下标和修改之后的值
连续的数列求完之后再遍历这个数组,若修改的数的下标落在x到y这个区间之内,则进行替换。
400000以内的数的质约数的最多只有7个,所以求连续的数列与p互质的和的时间复杂度是2*7*2^7,不超过1000次,遍历数组也不会超过1000次,所以对于任意一步操作计算的次数不超过2000次,再乘以1000步操作,所以计算量不会超过2000000次。
#include <iostream> #include <cstdio> #include <cmath> using namespace std; int n; int m; int yueshu[20]; int nyueshu; struct Node { int index; int value; }; Node node[1010]; int nnode; void Initialize() { nnode=0; } int IsCoprime(int a) { int i; for(i=1;i<=nyueshu;i++) { if(a%yueshu[i]==0) { return 0; } } return 1; } void GetYueshu(int p) { nyueshu=0; int a=(int)sqrt((double)p); int i; for(i=2;i<=a;i++) { if(p%i==0) { nyueshu++; yueshu[nyueshu]=i; } while(p%i==0) { p=p/i; } } if(p!=1) { nyueshu++; yueshu[nyueshu]=p; } } __int64 Get(__int64 a) { if(a==0) { return 0; } __int64 sum=(a+1)*a/2; int b[20]; int num=(int)pow((double)2,(double)nyueshu)-1; int i; int j; int temp; __int64 cj; int geshu; for(i=1;i<=num;i++) { temp=i; for(j=1;j<=nyueshu;j++) { b[j]=temp%2; temp=temp/2; } cj=1; geshu=0; for(j=1;j<=nyueshu;j++) { if(b[j]==1) { cj*=yueshu[j]; geshu++; } } if(geshu%2==1) { sum-=((1+a/cj)*(a/cj)/2*cj); } else { sum+=((1+a/cj)*(a/cj)/2*cj); } } return sum; } __int64 GetValue(int l,int r,int p) { GetYueshu(p); __int64 sum=Get(r)-Get(l-1); int i; for(i=1;i<=nnode;i++) { if(l<=node[i].index&&r>=node[i].index) { if(IsCoprime(node[i].index)==1) { sum-=node[i].index; } if(IsCoprime(node[i].value)==1) { sum+=node[i].value; } } } return sum; } void Insert(int index,int value) { int i; for(i=1;i<=nnode;i++) { if(node[i].index==index) { node[i].value=value; return ; } } nnode++; node[nnode].index=index; node[nnode].value=value; } int main() { int t; int T; int i; int operate; int l; int r; int p; int index; int value; scanf("%d",&T); for(t=1;t<=T;t++) { scanf("%d%d",&n,&m); Initialize(); for(i=1;i<=m;i++) { scanf("%d",&operate); if(operate==1) { scanf("%d%d%d",&l,&r,&p); printf("%I64d\n",GetValue(l,r,p)); } else { scanf("%d%d",&index,&value); Insert(index,value); } } } return 0; }