Sum
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1490 Accepted Submission(s): 432
Problem Description
XXX is puzzled with the question below:
1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.
Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).
Operation 2: change the x-th number to c( 1 <=c <= 400000).
For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.
1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.
Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).
Operation 2: change the x-th number to c( 1 <=c <= 400000).
For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.
Input
There are several test cases.
The first line in the input is an integer indicating the number of test cases.
For each case, the first line begins with two integers --- the above mentioned n and m.
Each the following m lines contains an operation.
Operation 1 is in this format: "1 x y p".
Operation 2 is in this format: "2 x c".
The first line in the input is an integer indicating the number of test cases.
For each case, the first line begins with two integers --- the above mentioned n and m.
Each the following m lines contains an operation.
Operation 1 is in this format: "1 x y p".
Operation 2 is in this format: "2 x c".
Output
For each operation 1, output a single integer in one line representing the result.
Sample Input
1 3 3 2 2 3 1 1 3 4 1 2 3 6
Sample Output
7 0
Source
Recommend
zhoujiaqi2010
本题初始化一1到n的序列,然后给出两种操作。
1,x,y,p表示在[x,y]的区间范围内求与p互质的数的和。
2.,x,c表示修改x处的数为c。
本题n<=400000,m<=1000.对于求[x,y]的区间范围内求与p互质的数的和。
若直接求互质的数,可能时间复杂度不允许。可以求与之不互质的数的和。先算出p的所有质因子,然后就是等差数列求和了。由于会出现重复,例如2,4,6,8,10……,3,6,9……的公共部分6.所有必须利用容斥原理。含奇数个质因数的加,含偶数个质因数的减。然后用区间[x,y]总和减去区间[x,y]与p不互质的数的和。注意本题还有个修改x处的值的操作。
本操作可以借助map容器,每次修改map[x]=c.然后在1操作时先遍历map容器;若p->first与p互质,则减去p->first;若p->second与p互质,则加p->second。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int MAXN=700;
int Prim[MAXN];
int Fac[MAXN];
int num_prim,n,num_fac;
//求最大公约数
int Grd(int a,int b)
{
return a%b?Grd(b,a%b):b;
}
//求所有的质数
void Prime()
{
int i,j,k;
num_prim=0;
for(i=2;i<MAXN;i++)
{
k=(int)sqrt(i*1.0);
for(j=2;j<=k;j++)
{
if(i%j==0)break;
}
if(j>k)Prim[num_prim++]=i;
}
}
//打印所有的质数
void Prim_print()
{
int i;
for(i=0;i<num_prim;i++)
{
if(i&&i%10==0)printf("\n");
printf("%d ",Prim[i]);
}
printf("\n*******************\n");
}
__int64 DFS(int en,__int64 tmp,int s,bool op)
{
int i;
__int64 ans=0,num=en/tmp;
if(op)ans+=((__int64)(num*tmp+tmp)*num)>>1;
else ans-=((__int64)(num*tmp+tmp)*num)>>1;
for(i=s+1;i<=num_fac;i++)
{
ans+=DFS(en,tmp*Fac[i],i,!op);
}
return ans;
}
__int64 Solve(int en,int p)
{
int i,j;
if(en==0)return 0;
__int64 ret=0;
int k=sqrt(p*1.0);
num_fac=0;
//求质因数
for(i=0;Prim[i]<=k;i++)
{
if(p%Prim[i]==0)
{
Fac[++num_fac]=Prim[i];
}
while(p%Prim[i]==0)
{
p/=Prim[i];
}
if(1==p)break;
}
if(p!=1)
{
Fac[++num_fac]=p;
}
/*for(i=1;i<=num_fac;i++)
printf("%I64d ",Fac[i]);
printf("\n11111111111111\n");*/
//用容斥原理求和
/************非递归写法*****************
int id=1<<num_fac;
for(i=1;i<id;i++)
{
__int64 tmp=1;
int cnt=0;
for(j=0;j<num_fac;j++)
{
if(i&1<<j)
{
tmp*=Fac[j+1];
cnt++;
}
}
// printf("tmp=%I64d\n",tmp);
__int64 t;
t=en/tmp;
tmp=((tmp+t*tmp)*t)>>1;
if(cnt&1)
ret+=tmp;
else ret-=tmp;
}
**********************************/
/*******************************************
递归求法
*****************************************/
for(i=1;i<=num_fac;i++)
ret+=DFS(en,Fac[i],i,true);
//printf("ret=%d\n",ret);
return ret;
}
map<int,int>Mat;
map<int,int>::iterator iter;
int main()
{
int m,a,b,p,op,cas;
Prime();
//Prim_print();
cin>>cas;
while(cas--)
{
scanf("%d%d",&n,&m);
Mat.clear();
while(m--)
{
scanf("%d",&op);
if(1==op)
{
scanf("%d%d%d",&a,&b,&p);
__int64 ans=0;
for(iter=Mat.begin();iter!=Mat.end();iter++)
{
if(iter->first>=a&&iter->first<=b)
{
ans-=(__int64)Grd(iter->first,p)==1?iter->first:0;
ans+=(__int64)Grd(iter->second,p)==1?iter->second:0;
}
}
ans+=((__int64)(a+b)*(b-a+1)/2-(Solve(b,p)-Solve(a-1,p)));
printf("%I64d\n",ans);
}
else
{
scanf("%d%d",&a,&b);
Mat[a]=b;
}
}
}
system("pause");
return 0;
}