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 }

 

posted @ 2012-09-24 22:40  Naix_x  阅读(309)  评论(0编辑  收藏  举报