百小度要和N个人PK,他们都有一个战斗力值,有如下规则
现在百小度有0~m范围的初始战斗力可选,他可以安排PK的顺序,问能否赢下N场PK
排序,为了快速提升战斗力,每次都找可以打败的最强对手进行PK
/** * Copyright © 2015 Authors. All rights reserved. * * FileName: A.cpp * Author: Beiyu Li <[email protected]> * Date: 2015-05-30 */
#include <cstdio>
#include <algorithm>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 10000 + 5;
int n, k;
LL m, a[maxn];
bool solve()
{
sort(a, a + n);
rep(i,n) {
if (a[i] > m) return false;
int j = i + 1;
while (j < n && a[j] <= m) ++j;
m = a[j-1] + k;
if (k) --k;
i = j - 1;
}
return true;
}
int main()
{
int T, cas = 0;
scanf("%d", &T);
while (T--) {
scanf("%d%lld%d", &n, &m, &k);
rep(i,n) scanf("%lld", &a[i]);
printf("Case #%d:\n", ++cas);
puts(solve()? "why am I so diao?": "madan!");
}
return 0;
}
对于一个数组,找出有多少个长度为K的区间,区间内的数排序后是连续的
扫描维护map,考察map里下标的个数,以及最大值减最小值加1,是否都等于K
/** * Copyright © 2015 Authors. All rights reserved. * * FileName: B.cpp * Author: Beiyu Li <[email protected]> * Date: 2015-05-30 */
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 10000 + 5;
const int maxk = 1000 + 5;
int n, m, k;
int a[maxn];
int res[maxk];
bool vis[maxk];
int solve()
{
if (vis[k]) return res[k];
vis[k] = true;
if (k > n) return res[k] = 0;
map<int, int> mp;
map<int, int>::iterator it;
rep(i,k-1) {
it = mp.find(a[i]);
if (it == mp.end()) mp[a[i]] = 1;
else ++it->second;
}
for (int i = k - 1; i < n; ++i) {
it = mp.find(a[i]);
if (it == mp.end()) mp[a[i]] = 1;
else ++it->second;
if (mp.rbegin()->first - mp.begin()->first + 1 == k
&& mp.size() == k) ++res[k];
it = mp.find(a[i-k+1]);
if (it->second == 1) mp.erase(it);
else --it->second;
}
return res[k];
}
int main()
{
int T = 1, cas = 0;
while (T--) {
scanf("%d%d", &n, &m);
rep(i,n) scanf("%d", &a[i]);
printf("Case #%d:\n", ++cas);
while (m--) {
scanf("%d", &k);
printf("%d\n", solve());
}
}
return 0;
}
将序列A调整为序列B,代价为max{abs(Ai - Bi)}
现在要将A调整为单调递增的序列B,问最小代价
二分答案后得到每个数的取值范围,判断时从左到右每次取尽量小的数
/** * Copyright © 2015 Authors. All rights reserved. * * FileName: C.cpp * Author: Beiyu Li <[email protected]> * Date: 2015-05-30 */
#include <cstdio>
#include <algorithm>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 100000 + 5;
int n;
int a[maxn];
bool check(int d)
{
int minv = -inf;
rep(i,n) {
if (minv >= a[i] + d) return false;
minv = max(minv + 1, a[i] - d);
}
return true;
}
int main()
{
int T, cas = 0;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
rep(i,n) scanf("%d", &a[i]);
int l = 0, r = 1000000;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("Case #%d:\n", ++cas);
printf("%d\n", r);
}
return 0;
}
有一个队列,以及三种操作:
回答询问
平衡树,对应insert、erase、select操作
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxe = 100000 + 5;
class SBT {
int psz;
struct Node {
int key, sz;
Node *ch[2];
void update() { sz = ch[0]->sz + ch[1]->sz + 1; }
} epool[maxe], *root, *null;
Node* new_node(int v, int s, Node *p)
{
Node *i = epool + psz++;
i->key = v; i->sz = s; i->ch[0] = i->ch[1] = p;
return i;
}
void rotate(Node* &u, bool o)
{
Node *v = u->ch[o];
u->ch[o] = v->ch[!o]; u->update();
v->ch[!o] = u; v->update();
u = v;
}
void maintain(Node* &u, bool o)
{
if (u == null) return;
Node* &v = u->ch[o];
if (v->ch[o]->sz > u->ch[!o]->sz) rotate(u, o);
else if (v->ch[!o]->sz <= u->ch[!o]->sz) return;
else rotate(v, !o), rotate(u, o);
maintain(u->ch[0], 0); maintain(u->ch[1], 1);
maintain(u, 0); maintain(u, 1);
}
void insert(Node* &u, int v)
{
if (u == null) {
u = new_node(v, 1, null);
return;
}
if (v == u->key) return;
bool o = v > u->key;
insert(u->ch[o], v);
maintain(u, o); u->update();
}
void erase(Node* &u, int v)
{
if (u == null) return;
if (u->key == v) {
if (u->ch[1] == null) { u = u->ch[0]; return; }
if (u->ch[0] == null) { u = u->ch[1]; return; }
Node *v = u->ch[1];
while (v->ch[0] != null) v = v->ch[0];
u->key = v->key;
erase(u->ch[1], v->key);
maintain(u, 0); u->update();
return;
}
bool o = v > u->key;
erase(u->ch[o], v);
maintain(u, !o); u->update();
}
int select(Node *u, int k)
{
while (true) {
int t = u->ch[0]->sz;
if (t == k) return u->key;
u = u->ch[t<k];
if (t < k) k -= t + 1;
}
}
int rank(Node *u, int v)
{
int res = 0;
while (true) {
if (u == null) break;
if (u->key < v) res += u->ch[0]->sz + 1;
u = u->ch[u->key<v];
}
return res;
}
public:
SBT()
{
null = new_node(0, 0, 0);
root = null->ch[0] = null->ch[1] = null;
}
~SBT() { clear(); }
int size() { return root->sz; }
bool empty() { return root == null; }
void clear() { root = null; psz = 1; }
void insert(int v) { insert(root, v); }
void erase(int v) { erase(root, v); }
int select(int k) { return select(root, k); }
int rank(int v) { return rank(root, v); }
} tree;
int main()
{
int n, cas = 0;
while (scanf("%d", &n) != EOF) {
printf("Case #%d:\n", ++cas);
queue<int> que;
tree.clear();
while (n--) {
char op[8];
scanf("%s", op);
if (op[0] == 'i') {
int x;
scanf("%d", &x);
que.push(x);
tree.insert(x);
} else if (op[0] == 'o') {
tree.erase(que.front());
que.pop();
} else if (op[0] == 'q') {
int k = (int)que.size() / 2;
printf("%d\n", tree.select(k));
}
}
}
return 0;
}
给出3阶魔方的操作序列,问多少次这样的操作后,魔方会复原
每种操作都是一个置换,得出操作序列的置换后,置换中所有环长度的lcm就是答案
#include <cstdio>
#include <algorithm>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
int face[256];
int c[6][9];
int h[] = {6, 3, 0, 7, 4, 1, 8, 5, 2};
int f[6][4] = {
{2, 4, 5, 1},
{0, 5, 3, 2},
{1, 3, 4, 0},
{1, 5, 4, 2},
{2, 3, 5, 0},
{0, 4, 3, 1}
};
int g[6][12] = {
{2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0},
{6, 7, 8, 0, 3, 6, 2, 1, 0, 8, 5, 2},
{0, 3, 6, 0, 3, 6, 8, 5, 2, 0, 3, 6},
{6, 7, 8, 6, 7, 8, 6, 7, 8, 6, 7, 8},
{0, 3, 6, 6, 7, 8, 8, 5, 2, 2, 1, 0},
{8, 5, 2, 0, 3, 6, 8, 5, 2, 8, 5, 2}
};
int mp[54];
bool vis[54];
void rotate(int o)
{
int t[12];
rep(i,9) t[i] = c[o][h[i]];
rep(i,9) c[o][i] = t[i];
rep(i,12) t[i] = c[f[o][((i/3)+3)%4]][g[o][(i+9)%12]];
rep(i,12) c[f[o][i/3]][g[o][i]] = t[i];
}
LL lcm(LL a, LL b) { return a / __gcd(a, b) * b; }
LL solve()
{
char s[128];
scanf("%s", s);
int n = strlen(s);
rep(o,6) rep(i,9) c[o][i] = o * 9 + i;
for (int i = 0; i < n; ++i) {
int o = face[s[i]], t = 1;
if (i + 1 < n && !isalpha(s[i+1])) {
++i;
if (s[i] == '\'') t = 3;
if (s[i] == '2') t = 2;
}
while (t--) rotate(o);
}
rep(o,6) rep(i,9) mp[o*9+i] = c[o][i];
LL res = -1;
memset(vis, false, sizeof(vis));
rep(i,54) if (!vis[i]) {
vis[i] = true;
int now = mp[i], c = 1;
while (now != i) {
vis[now] = true;
++c;
now = mp[now];
}
if (res == -1) res = c;
else res = lcm(res, c);
}
return res;
}
int main()
{
int T, cas = 0;
scanf("%d", &T);
face['U'] = 0; face['R'] = 1; face['F'] = 2;
face['D'] = 3; face['L'] = 4; face['B'] = 5;
while (T--) {
printf("Case #%d:\n", ++cas);
printf("%lld\n", solve());
}
return 0;
}
给出平面内N个点,找出能包围这N个点的最小矩形的面积
计算几何
先算出凸包,则只需要包围凸包上的点,且矩形的某条边与凸包的某条边共线
然后通过旋转卡壳,枚举共线的边,同时维护最左、最右及最上的3个点,计算并更新答案
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <complex>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
typedef long long LL;
typedef pair<int, int> Pii;
const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
int sgn(double x) { return x < -eps? -1: x > eps; }
typedef complex<double> Point;
typedef complex<double> Vector;
#define X real()
#define Y imag()
double dot(Vector u, Vector v) { return u.X * v.X + u.Y * v.Y; }
double cross(Vector u, Vector v) { return u.X * v.Y - u.Y * v.X; }
typedef vector<Point> Polygon;
bool on_left(Point p, const Polygon &g)
{
Point p1 = *++g.rbegin(), p2 = g.back();
return sgn(cross(p2 - p1, p - p1)) <= 0;
}
bool cmp(Point a, Point b) { return sgn(a.X - b.X)? a.X < b.X: a.Y < b.Y; }
void convex_hull(Point p[], int n, Polygon &g)
{
g.clear();
sort(p, p + n, cmp);
for (int i = 0; i < n; ++i) {
while (g.size() > 1 && on_left(p[i], g)) g.pop_back();
g.push_back(p[i]);
}
int k = g.size();
for (int i = n - 2; i >= 0; --i) {
while (g.size() > k && on_left(p[i], g)) g.pop_back();
g.push_back(p[i]);
}
if (n > 1) g.pop_back();
}
double prj(Point p, Point a, Point b)
{
return fabs(dot(b - a, p - a)) / abs(b - a);
}
double dis(Point p, Point a, Point b)
{
return fabs(cross(b - a, p - a)) / abs(b - a);
}
double min_box(Point p[], int n)
{
Polygon g;
convex_hull(p, n, g);
if (g.size() <= 2) return 0;
double res = 1e100;
int m = g.size(); g.push_back(g[0]);
for (int i = 0, r = 1, t = -1, l = -1; i < m; ++i) {
Vector v = g[i+1] - g[i];
while (sgn(dot(v, g[r+1] - g[r])) > 0) r = (r + 1) % m;
if (t == -1) t = r;
while (sgn(cross(v, g[t+1] - g[t])) > 0) t = (t + 1) % m;
if (l == -1) l = t;
while (sgn(dot(v, g[l+1] - g[l])) < 0) l = (l + 1) % m;
double w = fabs(dot(v, g[r] - g[l])) / abs(v);
double h = fabs(cross(v, g[t] - g[i])) / abs(v);
res = min(res, w * h);
}
return res;
}
const int maxn = 4000 + 5;
int n;
Point p[maxn];
int main()
{
int T, cas = 0;
scanf("%d", &T);
while (T--) {
scanf("%d", &n); n *= 4;
rep(i,n) {
int x, y;
scanf("%d%d", &x, &y);
p[i] = Point(x, y);
}
printf("Case #%d:\n", ++cas);
printf("%.0f\n", min_box(p, n));
}
return 0;
}