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数组做处理,对每个数(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;
}