前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >HDU-4407-Sum(容斥原理)「建议收藏」

HDU-4407-Sum(容斥原理)「建议收藏」

作者头像
全栈程序员站长
发布2022-07-08 19:52:25
发布2022-07-08 19:52:25
18900
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是全栈君。

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

代码语言:javascript
代码运行次数:0
复制
    1
3 3
2 2 3
1 1 3 4
1 2 3 6

Sample Output

代码语言:javascript
代码运行次数:0
复制
    7
0

Source

思路:m<=1000 和 数列初始状态为1,2,3,..n 是该题的突破口。

对于每一次询问。先不考虑数字被改动了。那我们能够直接用求和公式把x到y之间的数字的和求出来,然后再减去那些不和p互质的数(用容斥原理),再对改动过的数进行特判就可以。

代码语言:javascript
代码运行次数:0
复制
#include <stdio.h>

int num,idx[1005],val[1005],prime[10],p[40000];

inline bool check(int x)
{
    int i;

    for(i=0;i<num;i++) if(x%prime[i]==0) return 0;

    return 1;
}

int main()
{
    int T,n,m,i,j,k,type,cnt,a,b,c,last,lxdcnt,lxdnum,l,r;
    long long ans;

    //把40W以内的素数预处理出来-----------------
    cnt=0;

    for(i=2;i<400000;i++)
    {
        for(j=2;j*j<=i;j++) if(i%j==0) break;

        if(j*j>i) p[cnt++]=i;
    }
    //------------------------------------------

    scanf("%d",&T);

    while(T--)
    {
        scanf("%d%d",&n,&m);

        cnt=0;

        for(i=1;i<=m;i++)
        {
            scanf("%d",&type);

            if(type==1)
            {
                scanf("%d%d%d",&a,&b,&c);

                ans=(long long)(a+b)*(b-a+1)/2;

                num=0;//质因数的个数

                //获取c的质因数-----------------
                last=0;

                while(c>1)
                {
                    if(c%p[last]==0)
                    {
                        prime[num++]=p[last];
                        c/=p[last];
                        while(c%p[last]==0) c/=p[last];
                    }

                    last++;
                }
                //-------------------------------

                //容斥原理-------------------------
                for(j=1;j<(1<<num);j++)
                {
                    lxdcnt=0;
                    lxdnum=1;

                    for(k=0;k<num;k++) if(j&(1<<k))
                    {
                        lxdcnt++;
                        lxdnum*=prime[k];
                    }


                    l=a/lxdnum*lxdnum;
                    if(l<a) l+=lxdnum;
                    r=b/lxdnum*lxdnum;
                    if(r<l) continue;

                    if(lxdcnt&1) ans-=(long long)(l+r)*((r-l)/lxdnum+1)/2;
                    else ans+=(long long)(l+r)*((r-l)/lxdnum+1)/2;
                }
                //-----------------------------------

                //对改动过的数字特殊推断-----------------------------------
                for(j=0;j<cnt;j++)
                {
                    if(idx[j]>=a && idx[j]<=b)
                    {
                        if(!check(idx[j]))
                        {
                            if(check(val[j])) ans+=val[j];
                        }
                        else
                        {
                            if(check(val[j])) ans=ans+val[j]-idx[j];
                            else ans-=idx[j];
                        }
                    }
                }
                //--------------------------------------------------------

                printf("%I64d\n",ans);
            }
            else
            {
                scanf("%d%d",&a,&b);

                for(j=0;j<cnt;j++) if(idx[j]==a)//注意,改动的点可能之前已被改动过
                {
                    val[j]=b;
                    break;
                }

                if(j==cnt)
                {
                    idx[cnt]=a;
                    val[cnt++]=b;
                }
            }
        }
    }
}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/115923.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年1月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档