[容斥原理] hdu 4407 Sum

本文介绍了一道名为Sum的问题,该问题涉及数组操作和质数相关算法。具体包括求解区间内与给定数互质的所有数的和,以及更新指定位置的数值。通过分解质因数和运用容斥原理来高效解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4407

Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1817    Accepted Submission(s): 504


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.
 

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".
 

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   |   We have carefully selected several similar problems for you:   4822  4821  4820  4819  4818 
 

Statistic |  Submit |  Discuss |  Note

题目意思:

开始有1~n的n(n<=40000)个数,有两种操作

操作1: 1  x y p    求在区间[x,y]之间和p互质的所有数的和

操作2: 2  x  c      把x位置上的数改成c

解题思路:

简单容斥原理

实际上题目要求的就是求1~x间和p互质的数的总和。可以先把p分解质因数,然后用容斥原理求出与p不互质的总和,用总和减去即可。

至于改变,只需保存改变的数值,然后对每个查询扫一遍,单独处理改变的就行了。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#include<cmath>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 410000

bool isp[Maxn];
ll pri[Maxn],pp[Maxn],cnt0,cnt;
ll x,y;
ll ans1,ans2;
map<int,int>myp;
int cc,n,m,p;
struct Cha
{
    int old,ne;
}cha[1100];

void init()  //打质数表
{
    cnt=0;
    int N=400000;

    for(int i=1;i<=N;i++)
        isp[i]=true;
    for(int i=2;i<=N;i++)
    {
        if(isp[i])
        {
            pri[++cnt]=i;
            for(int j=i*2;j<=N;j+=i)
                isp[j]=false;
        }
    }
}
void cal(ll cur) //分解质因数
{
    cnt0=0;

    for(int i=1;pri[i]*pri[i]<=cur;i++)
    {
        if(!(cur%pri[i]))
        {
            pp[++cnt0]=pri[i];
            while(!(cur%pri[i]))
                cur/=pri[i];
        }
    }
    if(cur!=1)
        pp[++cnt0]=cur;

}
void dfs(ll hav,int cur,int num) //容斥原理求出不互质的
{
    if((hav>x&&hav>y)||cur>cnt0)
        return ;
    for(int i=cur;i<=cnt0;i++)
    {
        ll next=hav*pp[i];

        ll tt1=y/next,tt2=x/next;

        if(num&1)
        {
            ans1-=(1+tt1)*tt1/2*next;
            ans2-=(1+tt2)*tt2/2*next;
        }
        else
        {
            ans1+=(1+tt1)*tt1/2*next;
            ans2+=(1+tt2)*tt2/2*next;
        }
        dfs(next,i+1,num^1);

    }
}
ll gcd(ll a,ll b)
{
    if(a%b==0)
        return b;
    return gcd(b,a%b);
}
int main()
{

    //printf("%I64d\n",gcd(12,18));
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   init();

   int t;
   scanf("%d",&t);
   while(t--)
   {
       scanf("%d%d",&n,&m);
       myp.clear();
       cc=0;

       while(m--)
       {
           int a;

           scanf("%d",&a);
           if(a==1)
           {
               scanf("%I64d%I64d%I64d",&x,&y,&p);
               if(x>y)
                    swap(x,y);
               x--;   //注意x要减一
               cal(p);
               ll ans;
               ans1=(1+y)*y/2,ans2=(1+x)*x/2;

               for(int i=1;i<=cnt0;i++)
               {
                   ll tt1=y/pp[i],tt2=x/pp[i];

                   ans1-=(1+tt1)*tt1/2*pp[i];
                   ans2-=(1+tt2)*tt2/2*pp[i];

                   dfs(pp[i],i+1,0);
               }
               ans=ans1-ans2;
               for(int i=1;i<=cc;i++)
               {
                   if(cha[i].ne!=cha[i].old&&cha[i].old<=y&&cha[i].old>x) //要在[x,y]范围内找,x已经减了1
                   {
                       if(gcd(cha[i].old,p)==1) //之前已经加了
                            ans-=cha[i].old;
                       if(gcd(cha[i].ne,p)==1) //改了过后是否要加上
                            ans+=cha[i].ne;
                   }
               }
               printf("%I64d\n",ans);
           }
           else
           {
               scanf("%d%d",&x,&y);
               if(myp.find(x)==myp.end())
               {
                    ++cc;
                   myp[x]=cc;
                   cha[cc].ne=y,cha[cc].old=x;
               }
               else
                   cha[myp[x]].ne=y;

           }
       }

   }

   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值