AtCoder Regular Contest 092(部分)

C:2D Plane 2N Points

题意:红点和蓝点之间满足一个偏序关系那么就可以配对,但是蓝点最多只能和一个红点配对,每个红点也最多只能和一个蓝点配对,问最多能陪多少对


思路:可以配对的红点蓝点连一条边,二分图匹配一下就行了

#include
typedef long long ll;
const int maxn = 150;
using namespace std;

int use[maxn], from[maxn];
vector G[maxn];
int n, k;

int dfs(int x) {
    for(int i = 0; i < G[x].size(); i++) {
        int u = G[x][i];
        if(!use[u]) {
            use[u] = 1;
            if(from[u] == -1 || dfs(from[u])) {
                from[u] = x;
                return 1;
            }
        }
    }
    return 0;
}

int maxp() {
    memset(from, -1, sizeof(from));
    int sum = 0;
    for(int i = 1; i <= n; i++) {
        memset(use, 0, sizeof(use));
        sum += dfs(i);
    }
    return sum;
}

int a[maxn], b[maxn], c[maxn], d[maxn];

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < maxn; i++) G[i].clear();
        for(int i = 1; i <= n; i++) scanf("%d %d", &a[i], &b[i]);
        for(int i = 1; i <= n; i++) {
            scanf("%d %d", &c[i], &d[i]);
            for(int j = 1; j <= n; j++) {
                if(c[i] > a[j] && d[i] > b[j]) G[i].push_back(j);
            }

        }
        int ans = maxp();
        cout << ans << endl;
    }
    return 0;
}

D:Two Sequences

题意:N个数的a数组和b数组,对所有的ai + bj的异或和是多少

思路:可以统计每一个位上出现的1的数量,如果为奇数,那么那上面就是1,否则就是0,从低位往高位看起,看到第x位的时候,对b数组做处理,对每个数
记录bi / (1 << x)的最低位pi(只有0或者1), 还有bi % (1 << x)的值qi,按pi排序,那么考虑ai的时候,也类似计算出Pi, Qi,ai对x这个位上的1的贡献可以
这样算:
如果Pi = 0, 那么对b数组中能在x位上产生1的情况是这样的:
(1) pj = 0, (qj + Qi) >= (1 << x) (即产生了进位)

(2) pj = 1, (qj + Qi) < (1 << x) (即不产生进位)

#include
typedef long long ll;
const int maxn = 2e5 + 10;
using namespace std;

typedef pair pa;
int n, k;
ll a[maxn], b[maxn], c[maxn], d[maxn];
pa res[maxn];

int main() {
    while(scanf("%d", &n) != EOF) {
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        for(int j = 1; j <= n; j++) scanf("%lld", &b[j]);
        sort(a + 1, a + n + 1);
        sort(b + 1, b + n + 1);
        ll ans = 0;
        for(ll i = 0; i <= 30; i++) {
            ll x = (ll)1 << i;
            for(ll j = 1; j <= n; j++) {
                res[j - 1].first = (b[j] / x) & 1;
                res[j - 1].second = (b[j] % x);
            }
            sort(res, res + n);
            int id = 0;
            ll tot = 0;
            for(int ii = 0; ii < n; ii++) if(!res[ii].first) id = ii + 1;
            for(ll j = 1; j <= n; j++) {
                ll nx = (a[j] / x) & 1;
                ll ny = a[j] % x;
                if(nx == 0) {
                    ///为0要进位
                    ll c = (lower_bound(res, res + id, pa(0, x - ny)) - res);
                    tot += id - c;
                    ///为1不要进位
                    tot += lower_bound(res + id, res + n, pa(1, x - ny)) - (res + id);
                } else { ///不需要进位就有1
                    ///为0不需要进位
                    tot += lower_bound(res, res + id, pa(0, x - ny)) - res;
                    ///为1需要进位
                    ll ix = lower_bound(res + id, res +n, pa(1, x - ny)) - (res +id);
                    tot += n - (lower_bound(res + id, res + n, pa(1, x - ny)) - res);
                }
                //cout << "tot = " << tot << endl;
            }
            //cout << "tot = " << tot << endl;
            if(tot & 1) ans = ans | x;
        }
        cout << ans << endl;
    }
    return 0;
}

F:Two Faced Edges

题意:n个点m条边的有向图,对于每条边,如果改变它的方向,是否会改变原来图中的强连通分量的情况

思路:对于u -> v这条边,改变它的方向时,有以下两种情况
1.u, v属于相同的强连通分量时,那么需要保证原来u -> v的所有路径中在删除u->v这条边后还至少有一条路径可以从u到达v
2.u, v属于不同的强连通分量时,那么需要保证原来u -> v的所有路径中在删除u->v这条边后不存在一条路径可以从u到达v
也就是说, 对于情况1,如果之前v到u可达,那么改变边之后u还要可达v
对于情况2,如果之前v到u不可达,那么改变边之后u不能到达v

每一种情况的前者好求,dfs一遍就可以了,后者用深度优先搜索对邻接的边从前往后搜索一遍, 再从后往前搜索一遍, 看到达一个点的最先遍历到的边是否一样,如果一样那么就是只有一条路径可达, 否则就是有多条路径可达

#include
typedef long long ll;
const int maxn = 1e3 + 5;
const int INF = 1e9 + 10;
using namespace std;

struct P {
    int to, flag, id;
    P() {}
    P(int t, int f, int i) : to(t), flag(f), id(i) {}
};
int n, m, T, kase = 1;
vector

G[maxn]; bool can[maxn][maxn]; int min_flag[maxn], max_flag[maxn]; int ans[200 * maxn]; bool can_arrive(int x) { can[x][x] = true; queue que; que.push(x); while(!que.empty()) { int u = que.front(); que.pop(); for(int i = 0; i < G[u].size(); i++) { int to = G[u][i].to; if(can[x][to]) continue; can[x][to] = true; que.push(to); } } } void dfs(int x, int t, int flag) { if(flag == 0 && min_flag[x] != INF) return ; if(flag == 1 && max_flag[x] != -INF) return ; if(flag == 0) min_flag[x] = min(min_flag[x], t); if(flag == 1) max_flag[x] = max(max_flag[x], t); for(int i = 0; i < G[x].size(); i++) { int to = G[x][i].to; dfs(to, t, flag); } } void solve(int x) { for(int i = 1; i <= n; i++) { min_flag[i] = INF; max_flag[i] = -INF; } min_flag[x] = max_flag[x] = 0; for(int i = 0; i < G[x].size(); i++) { int to = G[x][i].to; dfs(to, G[x][i].flag, 0); } for(int i = G[x].size() - 1; i >= 0; i--) { int to = G[x][i].to; dfs(to, G[x][i].flag, 1); } for(int i = 0; i < G[x].size(); i++) { int flag = 1, to = G[x][i].to; if(min_flag[to] == max_flag[to]) flag = 0; if(can[to][x] != flag) flag = 0; else flag = 1; ans[G[x][i].id] = flag; } } int main() { while(scanf("%d %d", &n, &m) != EOF) { for(int i = 0; i < maxn; i++) G[i].clear(); for(int i = 1; i <= m; i++) { int u, v, sz; scanf("%d %d", &u, &v); sz = G[u].size() + 1; G[u].push_back(P(v, sz, i)); } memset(can, false, sizeof can); for(int i = 1; i <= n; i++) can_arrive(i); for(int i = 1; i <= n; i++) solve(i); for(int i = 1; i <= m; i++) printf("%s\n", ans[i] ? "same" : "diff"); } return 0; }


你可能感兴趣的:(其他)