2015 Astar Contest - Round 2A 题解

1001 超级赛亚ACMer

题目大意

百小度要和N个人PK,他们都有一个战斗力值,有如下规则

  • 百小度想赢,就必须使得自己的战斗力不小于对方
  • 如果百小度的战斗力大于对方,他以后的战斗力将保持在这个值
  • 如果百小度的战斗力等于对方,获胜后战斗力可以提升0~k点任意值
  • k有一个初始值,每战胜一次将减少1,但k最低只会减少到0

现在百小度有0~m范围的初始战斗力可选,他可以安排PK的顺序,问能否赢下N场PK

算法思路

排序,为了快速提升战斗力,每次都找可以打败的最强对手进行PK

时间复杂度: O(NlogN)

代码

/** * 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;
}

1002 找连续数

题目大意

对于一个数组,找出有多少个长度为K的区间,区间内的数排序后是连续的

算法思路

扫描维护map,考察map里下标的个数,以及最大值减最小值加1,是否都等于K

时间复杂度: O(MNlogK)

代码

/** * 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;
}

1003 序列变换

题目大意

将序列A调整为序列B,代价为max{abs(Ai - Bi)}
现在要将A调整为单调递增的序列B,问最小代价

算法思路

二分答案后得到每个数的取值范围,判断时从左到右每次取尽量小的数

时间复杂度: O(NlogN)

代码

/** * 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;
}

1004 KPI

题目大意

有一个队列,以及三种操作:

  1. 向队尾push一个数
  2. 从队头pop一个数
  3. 查询队列里所有数的中位数

回答询问

算法思路

平衡树,对应insert、erase、select操作

时间复杂度: O(MlogN)

代码

#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;
}

1005 三阶魔方

题目大意

给出3阶魔方的操作序列,问多少次这样的操作后,魔方会复原

算法思路

每种操作都是一个置换,得出操作序列的置换后,置换中所有环长度的lcm就是答案

时间复杂度: O(N)

代码

#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;
}

1006 矩形面积

题目大意

给出平面内N个点,找出能包围这N个点的最小矩形的面积

算法思路

计算几何
先算出凸包,则只需要包围凸包上的点,且矩形的某条边与凸包的某条边共线
然后通过旋转卡壳,枚举共线的边,同时维护最左、最右及最上的3个点,计算并更新答案

时间复杂度: O(NlogN+N)

代码

#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;
}

你可能感兴趣的:(题解,Astar2015)