HDU--4407(容斥原理)

2015-05-14 19:24:05

题目:给出一列数(1~n),然后有 m(m<=1000)个询问,每个询问有两种,(1)查询区间 [a,b] 中与 p 互素的数的和,(2)改第 x 个数为 c

总结:注意到 m 很小,所以直接对于每个查询,先用容斥处理,然后重新暴力处理之前的所有更改即可,上界:1000*1000。

  有个细节:如何一个点被更改多次,我们只用算最后一次的更改,可以用 map 来实现。(我的话比较傻X地标记已经处理过的位置)

 

map实现:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 1000;

int fact[MAXN],fcnt;
int T,n,m;
ll res;
map<int,int> mp;
map<int,int>::iterator it;

void Dfs(int top,int p,int v,int cnt){
    if(p > fcnt){
        if(cnt == 0) return;
        int num = top / v;
        ll cur = (ll)(num+1)*num/2*v;
        if(cnt & 1) res += cur;
        else res -= cur;
        return;
    }
    Dfs(top,p + 1,v,cnt);
    Dfs(top,p + 1,v * fact[p],cnt + 1);
}

int Gcd(int a,int b){
    while(a > 0 && b > 0)
        if(a > b) a %= b;
        else b %= a;
    return a + b;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        mp.clear();
        while(m--){
            int op,a,b,c;
            ll ans = 0;
            scanf("%d",&op);
            if(op == 1){
                scanf("%d%d%d",&a,&b,&c);
                fcnt = 0;
                int tc = c;
                for(int i = 2; i * i <= c; ++i) if(tc % i == 0){
                    fact[++fcnt] = i;
                    while(tc % i == 0) tc /= i;
                }
                if(tc != 1) fact[++fcnt] = tc;
                res = 0; Dfs(a - 1,1,1,0);
                ans -= (ll)a*(a-1)/2 - res;
                res = 0; Dfs(b,1,1,0);
                ans += (ll)(b+1)*b/2 - res;
                for(it = mp.begin(); it != mp.end(); it++){
                    int v1 = (*it).first,v2 = (*it).second;
                    if(v1 < a || v1 > b) continue;
                    if(Gcd(v1,c) == 1) ans -= v1;
                    if(Gcd(v2,c) == 1) ans += v2;
                }
                printf("%I64d\n",ans);
            }
            else{
                scanf("%d%d",&a,&c);
                mp[a] = c;
            }
        }
    }
    return 0;
}
View Code

 

标记位置:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 1000;

int fact[MAXN],fcnt;
int T,n,m;
int q[1010][2],qcnt;
ll res;
bool vis[400010];

void Dfs(int top,int p,int v,int cnt){
    if(p > fcnt){
        if(cnt == 0) return;
        int num = top / v;
        ll cur = (ll)(num+1)*num/2*v;
        //printf("v,cnt,num,cur:%d %d %d %d\n",v,cnt,num,cur);
        //printf("cur : %lld\n",cur);
        if(cnt & 1) res += cur;
        else res -= cur;
        return;
        //printf("res : %lld\n",res);
    }
    Dfs(top,p + 1,v,cnt);
    Dfs(top,p + 1,v * fact[p],cnt + 1);
}

int Gcd(int a,int b){
    while(a > 0 && b > 0)
        if(a > b) a %= b;
        else b %= a;
    return a + b;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        qcnt = 0;
        while(m--){
            int op,a,b,c;
            ll ans = 0;
            scanf("%d",&op);
            if(op == 1){
                scanf("%d%d%d",&a,&b,&c);
                fcnt = 0;
                int tc = c;
                for(int i = 2; i * i <= c; ++i) if(tc % i == 0){
                    fact[++fcnt] = i;
                    while(tc % i == 0) tc /= i;
                }
                if(tc != 1) fact[++fcnt] = tc;
                res = 0; Dfs(a - 1,1,1,0);
                ans -= (ll)a*(a-1)/2 - res;
                res = 0; Dfs(b,1,1,0);
                ans += (ll)(b+1)*b/2 - res;
                memset(vis,0,sizeof(vis));
                for(int i = qcnt; i >= 1; --i){
                    if(vis[q[i][0]] || q[i][0] < a || q[i][0] > b) continue;
                    vis[q[i][0]] = 1;
                    if(Gcd(q[i][0],c) == 1) ans -= q[i][0];
                    if(Gcd(q[i][1],c) == 1) ans += q[i][1];
                }
                printf("%I64d\n",ans);
            }
            else{
                scanf("%d%d",&a,&c);
                q[++qcnt][0] = a;
                q[qcnt][1] = c;
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2015-05-14 19:35  Naturain  阅读(134)  评论(0编辑  收藏  举报