hdu 4407 容斥原理

题意:

1  //一组数据

3 3    //数字为1-3,3次运算

2 2 3    //将2号位变成3

1 1 3 4    //计算1-3号位上与4互质的数的和

1 2 3 6

好题,需要重复练习

  1 //1008

  2 #include<stdio.h>

  3 #include<iostream>

  4 #include<map>

  5 #include<set>

  6 #include<algorithm>

  7 #include<string.h>

  8 #include<stdlib.h>

  9 using namespace std;

 10 

 11 int gcd(int a,int b)

 12 {

 13     if(b==0)return a;

 14     return gcd(b,a%b);

 15 }

 16 

 17 long long sum1(int x,int y,int p)//求区间[x,y]中p的倍数的和

 18 {

 19     if(p>y)return 0;

 20     int t1=x/p;

 21     int t2=y/p;

 22     if(t1*p<x)t1++;

 23     if(t2<t1)return 0;

 24     long long sum=0;

 25     sum=(long long)p*(t1+t2)*(t2-t1+1)/2;

 26     return sum;

 27 }

 28 

 29 const int MAXN=400000;

 30 int prime[MAXN+1];

 31 int getPrime()//得到小于等于MAXN的素数,prime[0]存放的是个数

 32 {

 33     memset(prime,0,sizeof(prime));

 34     for(int i=2;i<=MAXN;i++)

 35     {

 36         if(!prime[i]) prime[++prime[0]]=i;

 37         for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++)

 38         {

 39             prime[prime[j]*i]=1;

 40             if(i%prime[j]==0) break;

 41         }

 42     }

 43     return prime[0];

 44 }

 45 long long factor[100][2];

 46 int facCnt;

 47 int getFactors(long long x)//把x进行素数分解

 48 {

 49     facCnt=0;

 50     long long tmp=x;

 51     for(int i=1;prime[i]<=tmp/prime[i];i++)

 52     {

 53         factor[facCnt][1]=0;

 54         if(tmp%prime[i]==0)

 55         {

 56             factor[facCnt][0]=prime[i];

 57             while(tmp%prime[i]==0)

 58             {

 59                    factor[facCnt][1]++;

 60                    tmp/=prime[i];

 61             }

 62             facCnt++;

 63         }

 64     }

 65     if(tmp!=1)

 66     {

 67         factor[facCnt][0]=tmp;

 68         factor[facCnt++][1]=1;

 69     }

 70     return facCnt;

 71 }

 72 

 73 long long SS(int s,int x,int y)

 74 //求[x,y]之间是素因子倍数的和。素因子的状态是s,0表示没有这个素因子,

 75 //1表示有。容斥原理。先不管加减,先奇数加,偶数加,最后按照正负去调整就好了。

 76 {

 77     long long ans=0;

 78     int cnt=0;

 79     int p=1;

 80     for(int i=0;i<facCnt;i++)

 81     {

 82         if(s&(1<<i))

 83         {

 84             cnt++;

 85             p*=factor[i][0];        //由于类似2,3,会导致在计算6时重复计算,所以所有素因子都要计算一遍

 86         }

 87     }

 88     ans=sum1(x,y,p);

 89     //printf("%d %d * %d *\n",x,y,p);

 90     if(cnt%2)ans=-ans;

 91     //printf("**%lld\n",ans);

 92     return ans;

 93 }

 94 

 95 long long solve1(int x,int y,int p)//求[x,y]之间和p不互素的数的和

 96 {

 97     getFactors(p);

 98     long long ans=0;

 99     for(int i=1;i<(1<<facCnt);i++)

100       ans+=SS(i,x,y);

101     if(ans<0)ans=-ans;

102     return ans;

103 }

104 map<int,int>mp;

105 map<int,int>::iterator it;

106 

107 long long query(int x,int y,int p)//查询。改变被修改了的就可以了

108 {

109     long long ans=(long long)(x+y)*(y-x+1)/2;   //原本的和

110     long long temp=solve1(x,y,p);   //与p不互质的数的和

111     ans-=temp;

112     for(it=mp.begin();it!=mp.end();it++)

113     {

114         int t1=it->first;

115         if(t1<x||t1>y)continue;

116         int t2=it->second;

117         if(gcd(t1,p)==1)ans-=t1;//本来互素的要减掉

118         if(gcd(t2,p)==1)ans+=t2;//修改后互素的要加上

119     }

120     return ans;

121 }

122 int main()

123 {

124     getPrime();

125     #ifndef ONLINE_JUDGE

126     freopen("1.in","r",stdin);

127     #endif

128     int T;

129     int n,m;

130     int x,y,p;

131     int t;

132     scanf("%d",&T);

133     while(T--)

134     {

135         scanf("%d%d",&n,&m);

136         mp.clear();

137         while(m--)

138         {

139             scanf("%d",&t);

140             if(t==1)

141             {

142                 scanf("%d%d%d",&x,&y,&p);

143                 if(x>y)swap(x,y);

144                 printf("%I64d\n",query(x,y,p));

145             }

146             else

147             {

148                 scanf("%d%d",&x,&p);

149                 mp[x]=p;

150             }

151         }

152     }

153     return 0;

154 }

 

你可能感兴趣的:(HDU)