题目链接:hdu 4407
题意:
给一个长度为n的序列,序列由1~n依次组成。
对序列执行两种操作:
1.查询[x,y]内与p互素的数的和;
2.修改第x数为c.
题解:
这题我们可以先不管操作2,就按操作1去搞,因为数据很小,完全可以暴力解决操作2带来的问题,
那么我们可以求[1,n]内与p互素的和,最后结果就为 solve[1,y]-solve[1,x-1],再处理下操作2就行了,
求 [1,n]内与p互素的和,我们在另外一道题也做过,https://blog.csdn.net/LJD201724114126/article/details/82620754
简单改下就行了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=400010;
int prime[maxn],cnt; ///保存素数,素数的个数
bool book[maxn];
map<int ,int >mp;
vector<int> factor;
int gcd(int a,int b)
{
if(!b) return a;
else return gcd(b,a%b);
}
void Pri() ///线性筛素数
{
memset(book,0,sizeof(book));
cnt=0;
book[0]=book[1]=1;
for(int i=2;i<maxn;i++)
{
if(!book[i]) prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<maxn;j++){
book[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
inline LL F(LL k,LL n){
return n*(n+1)/2*k;
}
LL solve(int n) ///解决[1,n] 内与p互素的和
{
LL sum=F(1LL,n); ///计算前n项和
LL item=1<<factor.size(); ///素因子个数
LL ans=0;
for(int i=1;i<item;i++) ///二进制容斥,都差不多的
{
int num=0,x=1;
for(int j=0;j<factor.size();j++)
{
if(1&(i>>j)) {
num++;x*=factor[j];
}
}
if(num&1) ans+=F(x,n/x);
else ans-=F(x,n/x);
}
return sum-ans;
}
int main()
{
int ncase;
Pri();
scanf("%d",&ncase);
while(ncase--)
{
mp.clear(); ///注意此处,每次测试案例都要清零
int n,m;
scanf("%d%d",&n,&m);
while(m--){
int choice;
scanf("%d",&choice);
int x,y,c,p;
if(choice==1){
scanf("%d%d%d",&x,&y,&p);
if(x>y) swap(x,y);
factor.clear(); ///初始化
int item=p;
for(int i=0;i<cnt;i++) ///求出p的素因子
{
if(prime[i]>item) break;
if(item%prime[i]==0){
factor.push_back(prime[i]);
while(item%prime[i]==0)
item/=prime[i];
}
}
///这是另外一种求素因子的方法
// for(int i=2;i*i<=item;i++){
// if(item%i==0){
// factor.push_back(i);
// while(item%i==0) item/=i;
// }
// }
if(item>1) factor.push_back(item);
LL sum=solve(y)-solve(x-1);
// printf("%lld %lld\n",solve(y),solve(x-1));
map<int ,int >::iterator it;
for(it=mp.begin();it!=mp.end();it++) ///查找操作2对结果有没有影响
{
int a=it->first,b=it->second;
if(a>y||a<x) continue;
if(gcd(a,p)==1) sum-=a; ///本来互素的要减掉
if(gcd(b,p)==1) sum+=b;///修改后互素的要加上
// printf("a=%d,b=%d\n",a,b);
}
printf("%lld\n",sum);
}
else{
scanf("%d%d",&x,&c);
mp[x]=c;
}
}
}
return 8;
}
我的标签:做个有情怀的程序员。