HDU 4407 SUM 容斥原理

这个题目要求既对序列的某段区间求和p互质数目,又支持对某个数进行修改

一开始看到这个题,有点懵,就是因为第二个操作,如果只是第一个操作,并且是原始序列1-n,那就很简单了,按照之前写过的某个题目,求出1-y中的数目,减去1-x中的数目即可

就是第二个操作把序列打乱了,这样就不好搞了

后来还是大神博客的一句话,突然解决了问题,说:总的操作数只有1000,直接暴力搞定第二个操作就行啊

我想想,对啊,一开始只是按普通操作求出数目,然后遍历一下修改(都最多只有1000个),把修改对应投射到结果上,就行了啊。。。于是,迎仍而解。。。

怎么没想到可以暴力呢,太把第二个操作当回事了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define LL __int64
using namespace std;
const int N = 400010;
int change[N],n,m;
int calc[1010],cnt;
int prime[20],ret;
int gcd(int a,int b)
{
    if (a<b) swap(a,b);
    while (b)
    {
        int tmp=b;
        b=a%b;
        a=tmp;
    }
    return a;
}
void proc(int x)
{
    ret=0;
    for (int i=2;i*i<=x;i++){
        if (x%i==0){
          prime[ret++]=i;
          while (x%i==0) x/=i;
        }
    }
    if (x>1) prime[ret++]=x;
}
LL dfs(int d,int co,int sign,int x)
{
    if (d>=ret) return 0;
    LL sum=0;
    if (d>=0){
        LL res=x/co;
        if (res>0)
        sum=(LL)res*co+res*(res-1)/2*co;
        sum*=(LL)sign;
    }
    for (int i=d+1;i<ret;i++){
        sum+=dfs(i,co*prime[i],-sign,x);
    }
    return sum;
}
int main()
{
    int t,x,y,p,op;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        //memset(change,0,sizeof(change[0]*(n+2)));
        cnt=0;
        while (m--)
        {
            scanf("%d",&op);
            if (op==2){
                scanf("%d%d",&x,&y);
                change[x]=y;
                bool flag=0;
                for (int i=0;i<cnt;i++){
                    if (calc[i]==x) {flag=1;break;}
                }
                if (!flag) calc[cnt++]=x;
            }
            else{
                scanf("%d%d%d",&x,&y,&p);
                if (x>y) swap(x,y);
                proc(p);
                LL sum1=dfs(-1,1,-1,x-1);
                LL sum2=dfs(-1,1,-1,y);
                //cout<<sum1<<" "<<sum2<<endl;
                sum2-=sum1;
                LL all=(LL)(x+y)*(y-x+1)/2;
                all-=sum2;
                for (int i=0;i<cnt;i++){
                    if (calc[i]>=x && calc[i]<=y){
                        if (gcd(calc[i],p)==1) all-=(LL)calc[i];
                        if (gcd(change[calc[i]],p)==1) all+=(LL)change[calc[i]];
                    }
                }
                printf("%I64d
",all);
            }
        }
    }
}

  

原文地址:https://www.cnblogs.com/kkrisen/p/3961535.html