hdoj4407题解

  题目描述:1,2,3.....n排一行(1<=n<=400000),接下来有m(1<=m<=1000)操作,操作分为两种,一种是查询,一种是改值。

    查询:输入x,y,p,求第x个数到第y个数之间与p互质的数的和
    改值:输入x,c,将第x个数的值改为c

  这题用到容斥原理,先认为第x到第y个数是连续的,对于连续的数求与p互质的数的和可以用第x个数到第y个数的和减去与p有公约数的和。

      对于改值,用个数组记录下来要修改的数的下标和修改之后的值

      连续的数列求完之后再遍历这个数组,若修改的数的下标落在x到y这个区间之内,则进行替换。

  

  400000以内的数的质约数的最多只有7个,所以求连续的数列与p互质的和的时间复杂度是2*7*2^7,不超过1000次,遍历数组也不会超过1000次,所以对于任意一步操作计算的次数不超过2000次,再乘以1000步操作,所以计算量不会超过2000000次。

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n;
int m;
int yueshu[20];
int nyueshu;

struct Node
{
    int index;
    int value;
};
Node node[1010];
int nnode;

void Initialize()
{
    nnode=0;
}

int IsCoprime(int a)
{
    int i;
    for(i=1;i<=nyueshu;i++)
    {
        if(a%yueshu[i]==0)
        {
            return 0;
        }
    }
    return 1;
}


void GetYueshu(int p)
{
    nyueshu=0;
    int a=(int)sqrt((double)p);
    int i;
    for(i=2;i<=a;i++)
    {
        if(p%i==0)
        {
            nyueshu++;
            yueshu[nyueshu]=i;
        }
        while(p%i==0)
        {
            p=p/i;
        }
    }
    if(p!=1)
    {
        nyueshu++;
        yueshu[nyueshu]=p;
    }
}

__int64 Get(__int64 a)
{
    if(a==0)
    {
        return 0;
    }
     __int64 sum=(a+1)*a/2;
     int b[20];
     int num=(int)pow((double)2,(double)nyueshu)-1;
     int i;
     int j;
     int temp;
     __int64 cj;
     int geshu;
     for(i=1;i<=num;i++)
     {
          temp=i;
          for(j=1;j<=nyueshu;j++)
          {
              b[j]=temp%2;
              temp=temp/2;
          }
          cj=1;
          geshu=0;
          for(j=1;j<=nyueshu;j++)
          {
              if(b[j]==1)
              {
                  cj*=yueshu[j];
                  geshu++;
              }
          }
          if(geshu%2==1)
          {
               sum-=((1+a/cj)*(a/cj)/2*cj);
          }
          else
          {
              sum+=((1+a/cj)*(a/cj)/2*cj);
          }
     }
     return sum;
}

__int64 GetValue(int l,int r,int p)
{
    GetYueshu(p);
    __int64 sum=Get(r)-Get(l-1);
    int i;
    for(i=1;i<=nnode;i++)
    {
        if(l<=node[i].index&&r>=node[i].index)
        {
            if(IsCoprime(node[i].index)==1)
            {
                 sum-=node[i].index;
            }
            if(IsCoprime(node[i].value)==1)
            {
                sum+=node[i].value;
            }
        }
    }
    return sum;
}

void Insert(int index,int value)
{
    int i;
    for(i=1;i<=nnode;i++)
    {
        if(node[i].index==index)
        {
            node[i].value=value;
            return ;
        }
    }
    nnode++;
    node[nnode].index=index;
    node[nnode].value=value;
}

int main()
{
    int t;
    int T;
    int i;
    int operate;
    int l;
    int r;
    int p;
    int index;
    int value;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    { 
        scanf("%d%d",&n,&m);
        Initialize();
        for(i=1;i<=m;i++)
        {
            scanf("%d",&operate);
            if(operate==1)
            {
                scanf("%d%d%d",&l,&r,&p);
                printf("%I64d\n",GetValue(l,r,p));
            }
            else
            {
                scanf("%d%d",&index,&value);
                Insert(index,value);
            }
        }
    }
    return 0;
}
 

 

posted @ 2017-04-21 19:12  ezio_wg  阅读(222)  评论(0编辑  收藏  举报