【HDU】4407Sum-容斥原理加特判

本文探讨了一个涉及数列操作的问题,包括求线段内与特定数互质的数之和及替换数列中元素。通过使用等差数列求和公式、容斥原理和修改记录策略,文章提供了一种高效算法解决方案。

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

                        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:

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

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值