HDU 4407 Sum(容斥原理+状态压缩)
容斥原理不会,map不会,状态压缩不会。做毛线。。。
题目大意:给出1-n,n个数,有两个操作1是询问x-y区间上与p互质的数的和是多少,2是改变x位置上的数为c。
自己确实办不了,map这样用第一次见,容斥原来用的这么高端,状态压缩知道,但是这个运用的很神,多亏了宝哥讲解,代码实在是看都看不懂。。。
只有1000次的操作,先把x-y没有改变时候的情况下,求出,然后再计算在这个区间上是否有改变,这个用map来记录。然后就是求互质的问题了,这里要用到容斥原理,首先很明显两个数如果互质,则这两个数的质因子没有一个相同,所以只要把p的含有质因子的数在x-y上的和求出来,为了方便求1-y的然后减去1-(x-1),求的时候可能会求的重复了,比如6,即是2的倍数,3的倍数,会算两次,这时候就用到容斥原理了,操作很简单就是把1-x这些数里含有奇数个质因子的给加上,偶数个质因子给减去,原理我再思考一下。。画画图可能会好理解一点含有一个因子代表一个圆,含有两个因子的就是两个圆相交的部分,比如有n个这样的圆,我们要求是这些圆的实际的大小,全部加起来,就会有重复的部分多加了,这些圆有n-1部分含有两个因子,把这些部分再减去,就会多减了,就要再加上含有3个质因子的情况。。。直到达到因子个数。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <map> 7 #include <queue> 8 #include <set> 9 #include <vector> 10 #define M 400001 11 #define LL __int64 12 using namespace std; 13 int o[4000],prim[4000],num; 14 int gcd(int a,int b) 15 { 16 return b == 0 ? a:gcd(b,a%b); 17 } 18 map<int,int>mp; 19 map<int,int>::iterator it; 20 LL judge(int p,int x) 21 { 22 int i,j,len,tem,k; 23 LL ans = 1; 24 int yy[300]; 25 len = 0; 26 for(i = 1; i <= num-1; i ++) 27 { 28 if(p%prim[i] == 0) 29 yy[len++] = prim[i]; 30 while(p%prim[i] == 0) 31 p /= prim[i]; 32 if(p == 1)break; 33 } 34 if(p != 1)yy[len++] = p; 35 for(i = 1; i < 1<<len; i ++)//状态压缩,一共有len个引子所以转化为的二进制长度为len就行了。 36 { 37 tem = 1; 38 k = 0; 39 for(j = 0; j <= len-1; j ++) 40 { 41 if(i&(1<<j)) 42 { 43 tem *= yy[j]; 44 k ++; 45 } 46 } 47 int q = x/tem; 48 if(k%2) 49 { 50 ans += (((LL)1 + (LL)q)*(LL)q*(LL)tem)/2; 51 } 52 else 53 { 54 ans -= (((LL)1 + (LL)q)*(LL)q*(LL)tem)/2; 55 } 56 } 57 return ans; 58 } 59 LL getsum(int x) 60 { 61 LL y = x; 62 return (y+1)*y/2; 63 } 64 int main() 65 { 66 int t,n,m,i,j; 67 for(i = 2; i*i <= 660; i ++) 68 { 69 if(!o[i]) 70 { 71 for(j = i+i; j <= 660; j += i) 72 { 73 o[j] = 1; 74 } 75 } 76 } 77 for(i = 2,num = 1; i <= 660; i ++) 78 { 79 if(!o[i]) 80 { 81 prim[num++] = i; 82 } 83 } 84 scanf("%d",&t); 85 while(t--) 86 { 87 mp.clear(); 88 scanf("%d%d",&n,&m); 89 while(m--) 90 { 91 int x,y,p,c,ch; 92 LL ans; 93 scanf("%d",&ch); 94 if(ch == 1) 95 { 96 scanf("%d%d%d",&x,&y,&p); 97 ans = getsum(y) - getsum(x-1) - (judge(p,y)-judge(p,x-1)); 98 for(it = mp.begin(); it != mp.end(); it ++) 99 { 100 if((*it).first >= x&&y >= (*it).first) 101 { 102 if(gcd(p,(*it).first) == 1) 103 ans -= (*it).first; 104 if(gcd(p,(*it).second) == 1) 105 ans += (*it).second; 106 } 107 } 108 printf("%I64d\n",ans); 109 } 110 else if(ch == 2) 111 { 112 scanf("%d%d",&x,&c); 113 mp[x] = c; 114 } 115 } 116 } 117 return 0; 118 }