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 }

 

posted @ 2015-03-25 12:23  miao_a_miao  阅读(159)  评论(0编辑  收藏  举报