hdu 4407 Sum (容斥原理)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83107747

题目链接: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;
}








我的标签:做个有情怀的程序员。

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/83107747