1007-Friends and Enemies
用完全二分图表示朋友和敌人的关系,每个部分里的人和同一部分的其他人都是敌人,而与另一部分的人都是朋友,这样二分图的边就是不同鹅卵石的最大种类数,然后将这个与给出的种类数比较即可。
//1007
#include <cstdio>
int main(int argc, char const *argv[]) {
long long m, n;
while (scanf("%lld%lld", &m, &n) == 2) {
//完全二分图
puts((m / 2) * (m - m / 2) <= n ? "T" : "F");
}
return 0;
}
1006-Football Games
1006考察了兰道定理(Landau’s Theorem),先将分数从小到大排序一下,那么对任意前i个人的总分,必须不小于他们所能够得到的分数,即i*(i-1),同时总分必须是n*(n-1)。不过数据很水,各种奇淫巧技皆可….
#include <cstdio>
#include <algorithm>
using namespace std;
int b[20000+10];
int main(int argc, char const *argv[]) {
int m;
while (scanf("%d", &m) == 1) {
while (m--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
sort(b, b + n);
bool ok = true;
long long sum = 0;
for (int i = 1; i <= n; i++) {
sum += b[i];
if (sum < i * (i - 1)) {
ok = false;
break;
}
}
if (sum != n * (n - 1)) {
ok = false;
}
puts(ok ? "T" : "F");
}
}
return 0;
}
1009-Sparse Graph
给出一个图,每条边的权值都为1,求补图的最短路。
简单来说就是一边做出补图一边Bfs,最先Bfs到的即确定最短路。
//1009
#include <cstdio>
#include <set>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 10;
const int INF = 200000 + 10;
int n, m, s;
set<int> G[maxn];
int d[maxn];
void Bfs() {
//未被更新的点集
set<int> x;
for (int i = 0; i < n; i++) {
x.insert(i);
}
queue<int> q;
fill(d, d + n, INF);
d[s] = 0;
q.push(s);
x.erase(s);
while (!q.empty()) {
int u = q.front();
q.pop();
set<int> y;
set<int> :: iterator it;
for (it = x.begin(); it != x.end(); it++) {
if (G[u].find(*it) == G[u].end()) {
d[*it] = d[u] + 1;
y.insert(*it);
q.push(*it);
}
}
for (it = y.begin(); it != y.end(); it++) {
x.erase(*it);
}
y.clear();
}
}
int main(int argc, char const *argv[]) {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
u--, v--;
G[u].insert(v);
G[v].insert(u);
}
scanf("%d", &s);
s--;
Bfs();
for (int i = 0; i < n; i++) {
if (i == s) {
continue;
}
printf("%d", d[i]);
if (i != n - 1) {
putchar(' ');
}
}
putchar('\n');
for (int i = 0; i < n; i++) {
G[i].clear();
}
}
return 0;
}
1008-Function
给定一个区间[l,r],求a[l]%a[l+1]%…%a[r-1]%a[r]。
比如说a[l]%a[k],如果a[l]比a[k]小则值不变,因此要找到第一个小于等于a[i]的a[k]并取模,以取模后的新值继续向后寻找。
在不断的取模运算中,答案一定会以logn的方式递减(类比Gcd)…
为了快速找到我们所要的a[k],我们维护一个最小值线段树,通过线段树维护的值的大小二分的找到第一个比a[l]小的数。
//1008
#include <cstdio>
#include <algorithm>
using namespace std;
#define lchild rt << 1, l, m
#define rchild rt << 1 | 1, m + 1, r
const int maxn = 100000 + 10;
const int sz = 1 << 20;
int a[maxn];
int tree[sz];
int n;
void build(int rt = 1, int l = 1, int r = n) {
if (l == r) {
tree[rt] = a[l];
return;
}
int m = (l + r) >> 1;
build(lchild);
build(rchild);
tree[rt] = min(tree[rt<<1], tree[rt<<1|1]);
}
int query(int L, int R, int x, int rt = 1, int l = 1, int r = n) {
if (l == r) {
if (tree[rt] <= x) {
return l;
}
return -1;
}
int ret;
int m = (l + r) / 2;
if (m >= L && tree[rt<<1] <= x) {
if ((ret = query(L, R, x, lchild)) != -1) {
return ret;
} else if (m < R && tree[rt<<1|1] <= x) {
return query(L, R, x, rchild);
}
} else if (m < R && tree[rt<<1|1] <= x) {
return query(L, R, x, rchild);
}
return -1;
}
int main(int argc, char const *argv[]) {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
build();
int m;
scanf("%d", &m);
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
int x = a[l];
// 为什么不是l <= r?
while (l < r) {
l = query(l + 1, r, x);
if (l == -1) {
break;
}
x %= a[l];
}
printf("%d\n", x);
}
}
return 0;
}