Bestcoder #39

2015-05-03 16:16:11

总结:这场... 前面两题挺快,卡第三题了TAT。

 

A题 hdu 5210:贪心题。

  删k个数字,使得最后剩下的不同的数尽可能多。

  水题... 多扫几遍乱搞下就行。

#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 MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#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;

int n;
int v[105];

int main(){
    while(scanf("%d",&n) != EOF){
        MEM(v,0);
        for(int i = 1; i <= n; ++i){
            int a;
            scanf("%d",&a);
            v[a]++;
        }
        int k;
        scanf("%d",&k);
        for(int i = 1; i <= n; ++i){        
            while(k && v[i] > 1){
                v[i]--;
                k--;
            }
            if(k == 0) break;
        }
        for(int i = 1; i <= n; ++i) if(v[i]){
            if(k > 0){
                v[i]--;
                k--;
            }
            if(k == 0) break;
        }
        int cnt = 0;
        for(int i = 1; i <= n; ++i) if(v[i]) cnt++;
        printf("%d\n",cnt);
    }
    return 0;
}
View Code

 

B题 hdu 5211:筛法。

  对于每个数 a[i] ,找到一个 a[ki] (i < ki <= n)使得 a[i] | a[k],累加所有 ki。

  开计数数组,从左到右扫描,类似筛法,检查每个数的约数,累加,然后把计算过的赋值为0。

#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 MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#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;

int n;
int v[10010];
int vis[10010];

int main(){
    while(scanf("%d",&n) != EOF){
        for(int i = 1; i <= n; ++i) scanf("%d",&v[i]);
        MEM(vis,0);
        ll ans = 0;
        for(int i = 1; i <= n; ++i){
            int top = sqrt(1.0 * v[i]);
            for(int j = 1; j <= top; ++j) if(v[i] % j == 0){
                //j and v[i] / j
                if(vis[j]){
                    ans += vis[j] * i;
                    vis[j] = 0;
                }
                if(j == 1) continue;
                int tmp = v[i] / j;
                if(vis[tmp]){
                    ans += vis[tmp] * i;
                    vis[tmp] = 0;
                }
            }
            vis[v[i]]++;
        }
        cout << ans << endl;
    }
    return 0;
}
View Code

 

C题 hdu 5212:容斥+筛法。

  对于 N 个数里面的所有数对 (a[i] , a[j])(有顺序性),累加 gcd(a[i],a[j]) * (gcd(a[i],a[j]) - 1)。

  题解比较高端... 其实很简单...

  从大到小枚举 gcd ,然后用类似筛法的方法找出这个 gcd 的倍数的个数 k,那么这 k 个数的配对方式就有 k^2。

  注意到这些倍数中可能有已经计算过的 2×gcd 的倍数,所以要减掉 2×gcd 的倍数的个数,那么这就像一种容斥了。

  综合一下,用 num 表示一个数的倍数的个数,我们得到当前答案为 num(gcd) - num(2×gcd) - num(3×gcd) - .... - num(p×gcd) ,p×gcd <= max

#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 MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#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 ll mod = 10007;

int n;
int v[10010];
ll num[100010];

int main(){
    int a;
    while(scanf("%d",&n) != EOF){
        MEM(v,0);
        MEM(num,0);
        ll ans = 0;
        for(int i = 1; i <= n; ++i){
            scanf("%d",&a);
            v[a]++;
        }
        for(int i = 1; i <= 10000; ++i){
            for(int j = i; j <= 10000; j += i) num[i] += v[j];
        }
        for(int i = 10000; i >= 2; --i){
            ll cur = num[i] * num[i] % mod;
            for(int j = i + i; j <= 10000; j += i){
                cur = (cur - num[j] + mod) % mod;
            }
            num[i] = cur;
            ans = (ans + (ll)i * (i - 1) * num[i]) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}
View Code

 

D题 hdu 5213:莫队+容斥。

  给出 N 个数(数的范围:[1,N])以及常数 K,然后给出 M 个询问,每个询问四个数 l1,r1,l2,r2,求出 a[i] + a[j] == K 的方案数,其中 l1<=i<=r1 , l2<=j<=r2

  比较明显的莫队题,但是如果不会容斥转化还是不好做的...

  把每个询问的答案定义为:F(A,B) (A,B表示区间)

  由于每个询问涉及两个区间,莫队不方便直接做,所以努力将其转化为单区间询问问题,于是容斥应运而生~

  列出式子:F(A,B) = F(A+B+C,A+B+C) - F(A+C,A+C) - F(B+C,B+C) + F(C,C)

  那么只要把每个询问的两个区间拆分成四个区间来做即可~

  (小吐槽:用C++ wa了,用G++ ac了,还快了不少,有点醉.... >.<)

#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 = 30010;

int N,K,M,block;
int A[MAXN];
int num[MAXN];
ll cur_val;

struct Query{
    int l,r,id,bid;
    ll ans;
}q[MAXN << 2];

void Update(int l,int r,int d){
    for(int i = l; i <= r; ++i){
        num[A[i]] += d;
        if(A[i] < K) cur_val += num[K - A[i]] * d;
    }
}

bool cmp(Query a,Query b){ return a.bid == b.bid ? a.r < b.r : a.bid < b.bid; }
bool cmp_id(Query a,Query b){ return a.id < b.id; }

void Solve(){
    cur_val = 0;
    memset(num,0,sizeof(num));
    int tM = M << 2;
    sort(q + 1,q + tM + 1,cmp);
    for(int i = 1,l = 1,r = 0; i <= tM; ++i){
        if(q[i].l < l) Update(q[i].l,l - 1,1);
        if(l < q[i].l) Update(l,q[i].l - 1,-1);
        if(q[i].r < r) Update(q[i].r + 1,r,-1);
        if(r < q[i].r) Update(r + 1,q[i].r,1);
        q[i].ans = cur_val;
        l = q[i].l;
        r = q[i].r;
    }
    sort(q + 1,q + tM + 1,cmp_id);
    for(int i = 1; i <= tM; i += 4){
        printf("%I64d\n",q[i].ans - q[i+1].ans - q[i+2].ans + q[i+3].ans);
    }
}

int main(){
    int l1,r1,l2,r2;
    while(scanf("%d",&N) != EOF){
        block = (int)sqrt(1.0 * N);
        scanf("%d",&K);
        for(int i = 1; i <= N; ++i)
            scanf("%d",&A[i]);
        scanf("%d",&M);
        for(int i = 1; i <= M; ++i){
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            int cur = (i - 1) * 4 + 1;
            q[cur].bid = l1/block , q[cur].l = l1 , q[cur].r = r2;
            q[cur+1].bid = l1/block , q[cur+1].l = l1 , q[cur+1].r = l2-1;
            q[cur+2].bid = (r1+1)/block , q[cur+2].l = r1+1 , q[cur+2].r = r2;
            q[cur+3].bid = (r1+1)/block , q[cur+3].l = r1+1 , q[cur+3].r = l2-1;
            q[cur].id = cur;
            q[cur+1].id = cur+1;
            q[cur+2].id = cur+2;
            q[cur+3].id = cur+3;
        }
        Solve();
    }
    return 0;
}
    
View Code

 

posted @ 2015-05-03 16:48  Naturain  阅读(91)  评论(0编辑  收藏  举报