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 }

 

你可能感兴趣的:(HDU)