Sum HDU - 4407

原题链接

考察:容斥原理

这题完全不会....本蒟蒻连求出x~y区间p倍数的和都没想出来....虽然在质数距离那道题有涉及但是不完全想写那个公式.....

这道题也是HDU 1695 的变式,那道题是求[x,y]区间与x互质的个数,本质也是转化为1~y互质数-1~x的互质数.

参考大佬的思路:

        将[x,y]区间与p互质的和转换成[1,y]区间和-[1,x-1]区间和.这样好求很多.那么我们和就是求出[1,x]区间内不互质的数个数.用(1+n)*n/2再乘上相应的倍数即可.

        单点修改可以用map存储,当我们计算完和后就遍历一遍map,看是否需要修改.

注:不要遍历x~y,因为询问x可能很小而y很大.但是总操作数只有1000,也就是说map的size最多1000

时间复杂度: 1000*128*log1000 大约1e6

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <map>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N = 400010;
 8 vector<int> v[N];
 9 bool st[N];
10 map<int,int> mp;
11 void GetPrime(int n)
12 {
13     for(int i=2;i<=n;i++)
14     {
15         if(st[i]) continue;
16         v[i].push_back(i);
17         for(int j=2*i;j<=n;j+=i)
18         {
19             v[j].push_back(i);
20             st[j] = 1;
21         }
22     }
23 }
24 int gcd(int a,int b)
25 {
26     return b?gcd(b,a%b):a;
27 }
28 ll GetSum(int p,int s)
29 {
30     int sz = v[p].size(); ll ans = (ll)(1+s)*s/2;
31     for(int i=1;i<1<<sz;i++)
32     {
33         ll res = 1;int cnt = 0;
34         for(int j=0;j<sz;j++)
35         {
36             if(i>>j&1)
37             {
38                 if(res*v[p][j]>s) {res=-1;break; } 
39                 res*=(ll)v[p][j],cnt++;
40             }
41         }
42         if(res!=-1)
43         {
44             int k = s/res;
45             if(cnt&1) ans -=  (ll)(1+k)*k/2*res;
46             else ans+=(ll)(1+k)*k/2*res;
47         }
48     }
49     return ans;
50 }
51 int main()
52 {
53     GetPrime(N-10);
54     int T;
55     scanf("%d",&T);
56     while(T--)
57     {
58         int n,m; mp.clear();
59         scanf("%d%d",&n,&m);
60         for(int i=1;i<=m;i++)
61         {
62             int op,x,y; scanf("%d%d%d",&op,&x,&y);
63             if(op==1)
64             {
65                 int p; scanf("%d",&p);
66                 ll ans = GetSum(p,y)-GetSum(p,x-1);//1~n比x~y更好求
67                 for(auto& it:mp)
68                 {
69                     if(it.first>=x&&it.first<=y)
70                     {
71                         int i = it.first;
72                         int t = gcd(p,mp[i]),k = gcd(p,i);
73                         if(t==1) ans+=mp[i];
74                         if(k==1) ans-=i;
75                     }
76                 }
77                 printf("%lld\n",ans);
78             }else{
79                 mp[x] = y;
80             }
81         }
82     }
83     return 0;
84 }

 

还是得写点总结啊,不然写了白写..

总结:

  1. [x,y]区间求p倍数的和转化为[1,x]与[1,y]区间和的差
  2. p倍数的和可以将p倍数单独拎出来用(1+n)*n/2求和

时隔五个月复习我还是不会,主要卡在这几点:

  1. 与p互质的和还是没反应过来是对p质因数分解,学多了基础的反而不扎实了.
  2. 修改操作没反应过来可以存储修改操作,因为容斥是建立在1~n的基础上的,不进行容斥就只能一个个计算.
  3. 这里的map遍历是需要在函数外面,里面就莫名多遍历一遍.
posted @ 2021-01-31 21:47  acmloser  阅读(59)  评论(0编辑  收藏  举报