[容斥原理] hdu 4407 Sum

题意:

有两种操作1,2

1:询问 x,y区间能与p互质的数的和

2:将x改成p

一开始给N,初始是1~N个数

思路:

我们在求不互质的数有多少个的时候 其实就可以用等差数列求和求出这些数的和

那么我们到时候直接求一下就好了

然后因为这里的操作次数很少 所以我们可以标记一下哪些位置被修改过

然后在1操作的时候 特判一下这些位置

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
#define ll __int64
#define N 400000
int ss[N+2],v[N+2];
int mark[N+5][10],mcnt[N+5],c[10];
int used[N+5],change[N+5];
int n,chacnt;
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int ssb()
{
    int cnt=0;
    memset(ss,0,sizeof(ss));
    for(int i=2;i<=N;i++)
    {
        if(ss[i]==0)
        {
            for(int j=i+i;j<=N;j+=i) ss[j]=1;
            v[cnt++]=i;
        }
    }
    return cnt;
}
ll dfs(int k,int t,int lit,ll x,ll y,int p)
{
    ll ans=0;
    if(t==lit)
    {
        ll tep=1;
        for(int i=0;i<lit;i++) tep*=c[i];
        ll a=(tep+(x-1)/tep*tep)*((x-1)/tep)/2;
        ll b=(tep+y/tep*tep)*(y/tep)/2;
        return b-a;
    }
    for(int i=k+1;i<mcnt[p];i++)
    {
        c[t]=mark[p][i];
        ans+=dfs(i,t+1,lit,x,y,p);
    }
    return ans;
}
ll solve(ll x,ll y,int p)
{
    ll ans=0,tep=((1+y)*y/2)-((x)*(x-1)/2);
    for(int i=1;i<=mcnt[p];i++)
    {
        if(i%2) ans+=dfs(-1,0,i,x,y,p);
        else ans-=dfs(-1,0,i,x,y,p);
    }
    ans=tep-ans;
    for(int i=0;i<chacnt;i++)
    {
        if(change[i]>=x&&change[i]<=y)
        {
            if(gcd(change[i],p)==1) ans-=change[i];
            if(gcd(used[change[i]],p)==1) ans+=used[change[i]];
        }
    }
    return ans;
}
int main()
{
    int t,sscnt;
    cin>>t;
    sscnt=ssb();
    memset(mcnt,0,sizeof(mcnt));
    for(int i=0;i<sscnt;i++)
    {
        for(int j=v[i];j<=N;j+=v[i])
        {
            mark[j][mcnt[j]++]=v[i];
        }
    }
    while(t--)
    {
        int m;
        chacnt=0;
        scanf("%d%d",&n,&m);
        memset(used,0,sizeof(used));
        while(m--)
        {
            int f,x,y,p;
            scanf("%d",&f);
            if(f==1)
            {
                scanf("%d%d%d",&x,&y,&p);
                printf("%I64d\n",solve(x,y,p));
            }
            else
            {
                scanf("%d%d",&x,&p);
                if(used[x]==0) change[chacnt++]=x;
                used[x]=p;
            }
        }

    }
    return 0;
}
时间: 2024-10-17 04:05:45

[容斥原理] hdu 4407 Sum的相关文章

hdu 4407 Sum(容斥)

http://acm.hdu.edu.cn/showproblem.php?pid=4407 起初有n个数1~n,这里有m个操作,两种类型.操作1:求出[x,y]区间内与p互质的数的和.操作2:将第x位置的数变成y.对于每一个询问,输出结果. 因为只有1000次操作,而且起初是有序的.那么对于第i个询问,我们先忽略i之前的所有的第2种操作,即认为n个数为1~n,根据容斥原理求出[x,y]区间内与p互质的数之和,然后遍历i之前的操作2,对所求的答案进行调整即可.wa了无数次,改了好久,是因为我忽略

hdu 4407 Sum

http://acm.hdu.edu.cn/showproblem.php?pid=4407 题意:给定初始n个数1..n,两个操作,①1 x y p  询问第x个数到第y个数中与p互质的数的和; ②:2 x y  把第x个数变成y: 思路: 把p分解质因子,然后找出(1,pos)内与p不互质的,然后用的减去就是互质的和,第二个操作用到map映射,记录在那个位置改变之后的数. 1 #include <cstdio> 2 #include <cstring> 3 #include &

hdu 4407 Sum 容斥+离线

求X-Y之间和p互质的数的和,典型的容斥问题,求和用等差数列求和,注意首项末项是多少. 首先记录下不修改的答案,离线处理,存下询问,输出的时候,遇到一个操作1,就遍历前面的操作,把修改加上去,注意要判重,只保留最后一次修改. #include <stdio.h> #include <vector> #include <algorithm> #include <cmath> #include <iostream> #include<cstri

hdu 1258 Sum It Up (dfs+路径记录)

Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3953    Accepted Submission(s): 2032 Problem Description Given a specified total t and a list of n integers, find all distinct sums usi

[容斥原理] hdu 4135 Co-prime

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4135 Co-prime Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1176    Accepted Submission(s): 427 Problem Description Given a number N, you are a

HDU 4704 Sum( 费马小定理 )

HDU 4704 Sum( 费马小定理 ) 理解能力果然拙计,,题目看半天没懂什么意思. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MOD 1000000007 char str[100010]; LL fast_mod( LL a, int b) { LL res = 1; while( b )

hdu 4704 Sum (费马小定理+快速幂)

//(2^n-1)%mod //费马小定理:a^n ≡ a^(n%(m-1)) * a^(m-1)≡ a^(n%(m-1)) (mod m) # include <stdio.h> # include <algorithm> # include <string.h> # define mod 1000000007 using namespace std; __int64 pow(__int64 n) { __int64 p=1,q=2; while(n) { if(n%

[容斥原理] hdu 2204 Eddy&#39;s爱好

题意: 中文题目! 思路: 首先 M^k可以分解成 (M^(k*p)) p是素数 这么我们只要枚举素因子就好了 由于数据 所以只要枚举60以内的素数就够了 然后因为2*3*5*7就超过60了 做容斥原理就最多就只有三次 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #inclu

[容斥原理] hdu 2461 Rectangles

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2461 Rectangles Time Limit: 5000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1268    Accepted Submission(s): 665 Problem Description You are developing a soft