Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4264 Accepted Submission(s): 1222 Problem Description XXX is puzzled with the question below:
Input There are several test cases.
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 2012 ACM/ICPC Asia Regional Jinhua Online
Recommend zhoujiaqi2010 | We have carefully selected several similar problems for you: 6408 6407 6406 6405 6404 |
题目大意:
先给出一个元素为1~n的数列,有下面的两种操作
1.求某线段【a,b】上与p互质的数的和;
2.将某一个第个数x替换为y
思路:
对于第二个操作:我们可以用map记录修改的位置也就是数字为num,修改的为的数字为val
对于第一个操作:
1.可以用等差数列的求和公式求出其中所有数字的和,
2.容斥定理求出与其不互质的数的和,然后用全部数字的和减去不互质的数的和就是所求的互质的和
3.判断一下,之前的修改,如果修改的数字也就是位置num与p互质,那么要减去num,因为他已经被修改了,
如果修改为的数字val与p互质,那么要在答案上加上val,因为它与p互质。
完事了。。开 LL
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define ll long long
using namespace std;
int fac[10010];
int cnt;
ll gcd(ll a,ll b)
{
if(b==0) return a;
else
return gcd(b,a%b);
}
void factor(ll n)
{
cnt=0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
fac[cnt++]=i;
while(n%i==0)
n/=i;
}
}
if(n>1) fac[cnt++]=n;
}
ll getsum(ll n)
{
return n*(n+1)/2;
}
ll cal(ll n)
{
ll res=0;
for(int i=1;i<(1<<cnt);i++)
{
ll sum=1,flag=0;
for(int j=0;j<cnt;j++)
{
if(i&(1<<j))
flag++,sum*=fac[j];
}
if(flag&1)
{
res+=sum*getsum(n/sum);
}
else
{
res-=sum*getsum(n/sum);
}
}
return getsum(n)-res;
}
int main()
{
ll t;
cin>>t;
while(t--)
{
ll x,y,op;
ll n,m,p;
ll xx,yy;
map<ll,ll>mp;
map<ll,ll>::iterator it;
cin>>n>>m;
while(m--)
{
cin>>op;
if(op==2)
{
cin>>x>>y;
mp[x]=y;
}
else
{
cin>>xx>>yy>>p;
if(xx>yy)
swap(xx,yy);
factor(p);
ll ans=cal(yy)-cal(xx-1);
for(it=mp.begin();it!=mp.end();it++)
{
ll num=it->first,val=it->second;
if(num<xx||num>yy)
continue;
if(gcd(num,p)==1)
ans-=num;
if(gcd(val,p)==1)
ans+=val;
}
cout<<ans<<endl;
}
}
}
return 0;
}