2015长春网络赛 ACM/ICPC Asia Regional Changchun Online

1001 Alisha’s Party

题意: m个 t p 二元组对 表示t-th来到门前 放p个人进来 按照权值从大到小放  最终还要再开一次门把所有人放进来

分析: 优先队列或者set模拟 然后注意二元组要先排序。。。 赛上因为这个wa了好几发

代码:

//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1.5e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, m, q;
char name[N][205];
int val[N];

struct Query {
    int t, p;
    Query() {}
    Query(int t, int p): t(t), p(p) {}
    bool operator< (const Query& rhs) const {
        return t < rhs.t;
    }
} A[N];

int Q[N];

bool vis[N];
int ans[N];

void solve(int Max) {
    set<pair<int, int> > s;
    int rnk = 0, j = 1;
    for(int i = 1; i <= m; ++i) {
        for(; j <= A[i].t; ++j)
            s.insert(make_pair(val[j], -j));
        for(int k = 1; k <= A[i].p; ++k) {
            if(s.empty()) break;
            auto iter = s.end(); --iter;
            if(vis[++rnk]) {
                ans[rnk] = -iter->second;
//                printf("%d\n", -iter->second);
            }
            if(rnk == Max) return;
            s.erase(iter);
        }
    }
    for(; j <= n; ++j) s.insert(make_pair(val[j], -j));
    while(s.size()) {
        auto iter = s.end(); --iter;
        if(vis[++rnk]) {
            ans[rnk] = -iter->second;
//          printf("%d\n", -iter->second);
        }
        if(rnk == Max) return;
        s.erase(iter);
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d%d", &n, &m, &q);
        for(int i = 1; i <= n; ++i)
            scanf("%s%d", name[i], val + i);
        for(int i = 1; i <= m; ++i) {
            int x, y; scanf("%d%d", &x, &y);
            A[i] = Query(x, y);
        }
        sort(A + 1, A + 1 + m);

        int Max = 0;
        memset(vis, false, sizeof vis);
        for(int i = 1; i <= q; ++i) {
            scanf("%d", Q + i);
            vis[Q[i]] = true;
            Max = max(Max, Q[i]);
        }
        solve(Max);
        for(int i = 1; i <= q; ++i)
            printf("%s%c", name[ans[Q[i]]], " \n"[i == q]);
    }
    return 0;
}

1002 Ponds

题意: 不断删去度小于2的点 求剩余图中 连通分量里点的个数为奇数的 总权和
分析: 搞个队列乱搞就行了  注意push的时候 判断vis 不然会MLE
代码:
//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e4 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int M = 1e5 + 10;

int n, m;
int deg[N], val[N];

vector<int> G[N];
bool vis[N];

void dfs(int u, int &cnt, long long& sum) {
    sum += val[u];
    ++cnt;
    vis[u] = true;
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if(vis[v]) continue;
        dfs(v, cnt, sum);
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", val + i);
            G[i].clear();
            vis[i] = false;
            deg[i] = 0;
        }
        for(int i = 1; i <= m; ++i) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
            ++deg[u], ++deg[v];
        }

        queue<int> q;
        for(int i = 1; i <= n; ++i)
            if(deg[i] < 2) q.push(i);
        while(q.size()) {
            int u = q.front(); q.pop();
            deg[u] = 0; vis[u] = true;
            for(int i = 0; i < G[u].size(); ++i) {
                int v = G[u][i];
                if(--deg[v] < 2 && !vis[v]) q.push(v);
            }
        }

        long long ans = 0;
        for(int i = 1; i <= n; ++i) {
            if(vis[i]) continue;
            int cnt = 0; long long sum = 0;
            dfs(i, cnt, sum);
            if(cnt & 1) ans += sum;
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

1005 Travel

题意: 就是求q次询问 对于所有路径每条边权不超过d 的(s,t)起终点二元组的个数

分析: 离线询问 然后并查集 其实就是求连通分量里点的个数 然后求个C_n_2  (a,b) (b,a)算不同的 不除就行了

          赛上因为没有按秩合并就莫名跪了好多发 至今不知道为啥

代码: 

//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 2e4 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int M = 1e5 + 10;

int n, m, q;
long long ans[5005];
struct Edge {
    int u, v, c;
    Edge() {}
    Edge(int u, int v, int c) : u(u), v(v), c(c) {}
    bool operator< (const Edge& rhs) const {
        return c < rhs.c;
    }
} G[M];
struct Query {
    int d, id;
    Query() {}
    Query(int d, int id): d(d), id(id) {}
    bool operator< (const Query& rhs) const {
        return d < rhs.d;
    }
} Q[5005];

long long now;
int par[N], rnk[N], num[N];

int find(int x) {
    return par[x] == x ? x : find(par[x]);
}

void unite(int x, int y) {
    x = find(x); y = find(y);
    if(x == y) return;
    now += num[x] * num[y];
    if(rnk[x] < rnk[y]) {
        par[x] = y;
        num[y] += num[x]; num[x] = 0;
    } else {
        par[y] = x;
        if(rnk[x] == rnk[y]) ++rnk[x];
        num[x] += num[y]; num[y] = 0;
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%d%d", &n, &m, &q);
        for(int i = 0; i < m; ++i) {
            int u, v, c; scanf("%d%d%d", &u, &v, &c);
            G[i] = Edge(u, v, c);
        }
        sort(G, G + m);
        for(int i = 0; i < q; ++i) {
            int x; scanf("%d", &x);
            Q[i] = Query(x, i);
        }
        sort(Q, Q + q);

        for(int i = 1; i <= n; ++i) {
            par[i] = i;
            rnk[i] = 0;
            num[i] = 1;
        }

        memset(ans, 0, sizeof ans);
        now = 0;
        for(int i = 0, j = 0; i < q; ++i) {
            int cur = Q[i].d;
            while(j < m) {
                Edge &e = G[j];
                if(e.c <= cur) {
                    unite(e.u, e.v);
                } else break;
                ++j;
            }
            ans[Q[i].id] = now;
        }
        for(int i = 0; i < q; ++i) printf("%I64d\n", ans[i] * 2);
    }
    return 0;
}

1007 The Water Problem

题意: 区间RMQ裸题

分析: 线段树或者ST都行

代码:

//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, q, dp[2][N][20];

int RMQ(int l, int r) {
    int k = 31 - __builtin_clz(r - l + 1);
    int Max = max(dp[1][l][k], dp[1][r - (1 << k) + 1][k]);
//    int Min = min(dp[0][l][k], dp[0][r - (1 << k) + 1][k]);
    return Max;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &dp[0][i][0]);
            dp[1][i][0] = dp[0][i][0];
        }
        for(int j = 1; (1 << j) <= n; ++j) {
            for(int i = 1; i + (1 << j) - 1 <= n; ++i) {
                dp[0][i][j] = min(dp[0][i][j - 1],
                                  dp[0][i + (1 << j - 1)][j - 1]);
                dp[1][i][j] = max(dp[1][i][j - 1],
                                  dp[1][i + (1 << j - 1)][j - 1]);
            }
        }
        scanf("%d", &q);
        while(q--) {
            int x, y; scanf("%d%d", &x, &y);
            printf("%d\n", RMQ(x, y));
        }
    }
    return 0;
}

1008 Elven Postman

题意: 构建二叉搜索树 然后搜出特定点的路径

分析: - - 构建二叉树的只是 还是很简单的 O(n^2)可过  集训队里有一个O(nlogn)的建树办法 曾经有过一道10^5数据的题 被下面这个n^2的水过去了

代码:

//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, q;
int sz, ls[N], rs[N], val[N];

int newNode(int x) {
    ++sz;
    ls[sz] = rs[sz] = 0;
    val[sz] = x;
    return sz;
}

int insert(int rt, int x) {
    if(!val[rt]) return newNode(x);
    if(x < val[rt]) ls[rt] = insert(ls[rt], x);
    else rs[rt] = insert(rs[rt], x);
    return rt;
}

void dfs(int rt, int x) {
    if(x < val[rt]) {
        putchar('E');
        dfs(ls[rt], x);
    } else if(x > val[rt]) {
        putchar('W');
        dfs(rs[rt], x);
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        sz = 0;  memset(val, 0, sizeof val);
        for(int i = 1; i <= n; ++i) {
            int x; scanf("%d", &x);
            insert(1, x);
        }
        scanf("%d", &q);
        while(q--) {
            int x; scanf("%d", &x);
            dfs(1, x);
            puts("");
        }
    }
    return 0;
}

1010 Unknown Treasure

题意: 求解大组合数对多个质数乘积取模

分析: Lucas + CRT模版题  注意CRT合并的时候会炸longlong 需要模拟LL*LL的乘法

代码: 队友写的我贴个板子

//
//  Created by TaoSama on 2015-09-13
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
const int M = 1e5 + 10;

typedef long long ll;

ll n, m, k;
ll a[12], mm[12];

ll quick_mod(ll a, ll b, ll p) {
    ll ans = 1;
    a %= p;
    while(b) {
        if(b & 1) ans = ans * a % p;
        b >>= 1;
        a = a * a % p;
    }
    return ans;
}

ll C(ll n, ll m, ll p) {
    if(m > n) return 0;
    ll ans = 1;
    for(int i = 1; i <= m; i++) {
        ll a = (n + i - m) % p;
        ll b = i % p;
        ans = ans * (a * quick_mod(b, p - 2, p) % p) % p;
    }
    return ans;
}

ll Lucas(ll n, ll m, ll p) {
    if(m == 0) return 1;
    return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}

ll Extended_Euclid(ll a, ll b, ll &x, ll &y) {
    ll d;
    if(b == 0) {
        x = 1; y = 0;
        return a;
    }
    d = Extended_Euclid(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll mod_mul(ll a, ll b, ll mod) {
    ll ret = 0;
    while(b) {
        if(b & 1)    ret = (ret + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ret;
}
ll CRT() {
    ll d, x, y, tmp, M, ret;
    ret = 0;
    M = 1;
    for(int i = 0; i < k; i++)
        M *= mm[i];
    for(int i = 0; i < k; i++) {
        tmp = M / mm[i];
        d = Extended_Euclid(mm[i], tmp, x, y);
        ll temp = mod_mul(y, tmp, M);
        temp = mod_mul(temp, a[i], M);
        ret = (ret + temp) % M;
        //ret=(ret+y*tmp*a[i])%M;
    }
    return (M + ret) % M;
}
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    int T; cin >> T;
    while(T--) {
        cin >> n >> m >> k;
        for(int i = 0; i < k; i++) {
            cin >> mm[i];
            a[i] = Lucas(n, m, mm[i]);
        }
        cout << CRT() << endl;
    }
    return 0;
}


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值