【套题】2015ACM/ICPC亚洲区长春站 HDU5532 5533 5534 5536 5538

  • 水几个题,熟悉一下键盘。。。
  • HDU5532 Almost Sorted Array
  • 题意: ASA 定义为,仅去掉一个( One and Only One )元素后数组是非降序或者非升序。
  • 题解:很明显,判断一个序列是否有序可以通过判断其 Longest NonDecreasing Subsquence 或者 Longest NonIncreasing Subsquence 是否等于序列长度来得到。
/* **********************************************

    File Name: test.cpp

    Auther: [email protected]

    Created Time: 2015/11/1 12:34:01

*********************************************** */
#include 
using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int INF = 0xfffffff;
const int MAX = 100007;
int a[MAX];
int dp[MAX]; //dp[i] length is i min

int inc(int n) {
    fill(dp, dp + n + 1, INF);
    dp[0] = -INF;
    for (int i = 1; i <= n; ++i) {
        int sz = upper_bound(dp, dp + i, a[i]) - dp;
        //printf("get %d\n", sz);
        dp[sz] = a[i];
    }
    for (int i = n; i >= 1; --i) {
        if (dp[i] < INF) {
            return i;
        }
    }
    return 0;
}

int dec(int n) {
    reverse(a + 1, a + n + 1);
    return inc(n);
}

int main() {
    int T, n;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf(" %d", a + i);
        }
        puts((inc(n) >= n - 1 || dec(n) >= n - 1) ? "YES" : "NO");
    }
    return 0;
}
  • HDU5233 Dancing Stars on Me
  • 题意:求一堆点是否构成一个正 n 边形
  • 题解:求凸包,判断一下
    • 凸包顶点个数是否为 n
    • 凸包所有边是否等长
/* **********************************************

  File Name: 5533.cpp

  Auther: [email protected]

  Created Time: 2015年11月02日 星期一 20时33分46秒

*********************************************** */
#include 
using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const double INF = FLT_MAX;
const double EPS = 1e-8;
const double PI = acos(-1.0);
const int MAX = 107;

inline int sign(double x) {
    if (fabs(x) < EPS) return 0;
    if (x > 0.0) return 1;
    return -1;
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}
    Point operator-(const Point& ne)const {
        return Point(x - ne.x, y - ne.y);
    }
    Point operator+(const Point& b)const {
        return Point(x + b.x, y + b.y);
    }
    Point operator*(const double t)const {
        return Point(t * x, t * y);
    }
    Point operator/(const double t)const {
        if (sign(t) == 0) return Point(INF, INF);
        return Point(x / t, y / t);
    }
    double operator^(const Point& b)const {
        return (x - b.x) * (x - b.x) + (y - b.y) * (y - b.y);
    }
} ping[MAX];

struct Polygon {
    Point p[MAX];
    int n;
} ans;

inline double xmult(Point o, Point a, Point b) {
    return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y);
}

bool cmp(const Point& a, const Point& b) {
    return a.x < b.x || (sign(a.x - b.x) == 0 && a.y < b.y);
}

void convex_hull(Point p[MAX], int n, Polygon& res) {
    res.n = 0;
    sort(p, p + n, cmp);
    int i, j, top;
    for (i = 0, top = 0; i < n; ++i) {
        while (top > 1 && xmult(res.p[top - 2], res.p[top - 1], p[i]) < EPS) {
            --top;
        }
        res.p[top++] = p[i];
    }
    j = top;
    for (i = n - 2; i >= 0; --i) {
        while (top > j && xmult(res.p[top - 2], res.p[top - 1], p[i]) < EPS) {
            --top;
        }
        res.p[top++] = p[i];
    }
    res.n = top - 1;
}

int main() {
    int T, n;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %d", &n);
        for (int i = 0; i < n; ++i) {
            scanf(" %lf %lf", &ping[i].x, &ping[i].y);
        }
        convex_hull(ping, n, ans);
        if (n < 3 || ans.n != n) {
            puts("NO");
            continue;
        }
        double leng = ans.p[0] ^ ans.p[n - 1];
        bool flag = true;
        for (int i = 0; i < n - 1; ++i) {
            if (sign((ans.p[i] ^ ans.p[i + 1]) - leng)) {
                flag = false;
                break;
            }
        }
        puts(flag ? "YES" : "NO");
    }
    return 0;
}
  • HDU5534 Partial Tree
  • 题意: n 个点连成一棵树,对某个顶点 v ,若其度为 degv ,则价值为 fdegv
  • 题解: n 个点, n1 条边,共有 2n2 个度需要分配。可以证明,首先对每个顶点赋一个度,将剩余的 n2 个度任意分配给剩下的顶点,均可以得到一棵树。我们可以简单地反证一下~

    • 对每个顶点,最少可能分配到 1 个度,最多可能分配到
      1+(n2)=n1
      个度,这是满足任意一个顶点的度的限制条件 1degvn1 的。
    • 2n2 个度分配完后,我们可以开始两两顶点连边,每连一条边,二者的度分别减 1 ,先不考虑是否会造成环,那么
      • ① 当仅剩 2 个度时,将对应的两个点连一条边,即完成连边
      • ② 当多余 2 个度时,假设剩余 k 个度,只需要任意选择两个度还没用完的点连接起来,就可以达到度剩余 k2 的局面
    • 由①②可知, 恰好可以连出
      2n22=n1
      条边。此时,根据我们开始的分配,没有任何一个点是没有连至少一条边的,于是不可能存在孤立顶点;另外,,,,窝好像不能证明整个图的连通性鸭(;′⌒`)。。。
    • 于是可以换一个方向考虑,窝们考虑一个放射形图案,一个点度为 n1 ,作为根,其他所有点都是它的孩子,此时为 1+1++(n1) 的组合,将一个点拿下,连到其它点上,变成 1+1++2+(n2) 的组合,相当于最后的 n2 个度分了 1 个出去,如此下去,可以达到将 n2 分解的任何一种组合。
  • 题解续:做完上述分析,我们就可以先考虑一个简化版本了。容量为 n2 的背包,有 n1 件物品,分别为大小为 i ,价值为 fi ,有无限多个,问装满背包最大获得价值为多少。

/* **********************************************

  File Name: 5534.cpp

  Auther: [email protected]

  Created Time: 2015/11/3 22:22:19

*********************************************** */
#include 
using namespace std;

typedef pair<int, int> P;

const int INF = 0xfffffff;
const int MAX = 2018;
vector

bag; int dp[MAX]; int f[MAX]; int m; void push(int weight, int value) { for (int i = 1; i * weight <= m; i <<= 1) { bag.push_back(P(weight * i, value * i)); //printf("push (%d, %d)\n", weight * i, value * i); } } int main() { int T, n; scanf(" %d", &T); while (T--) { bag.clear(); scanf(" %d", &n); m = n - 2; for (int i = 1; i < n; ++i) { scanf(" %d", f + i); } int ans = n * f[1]; for (int i = 2; i < n; ++i) { push(i - 1, f[i] - f[1]); } sort(bag.begin(), bag.end()); unique(bag.begin(), bag.end()); fill(dp, dp + m + 1, -INF); dp[0] = 0; for (int i = 0; i < bag.size(); ++i) { for (int j = m; j >= bag[i].first; --j) { if (dp[j - bag[i].first] + bag[i].second > dp[j]) { dp[j] = dp[j - bag[i].first] + bag[i].second; } } } printf("%d\n", dp[m] + ans); } return 0; }

  • HDU5536 Chip Factory
  • 题意:问最大的
    (si+sj)sk
  • 题解:将所有数归一化为 32 bit 的串,建立 Trie 树求解即可。复杂度 log(n2)n
/* **********************************************

  File Name: 5536.cpp

  Auther: [email protected]

  Created Time: 2015/11/3 21:38:44

*********************************************** */
#include 
using namespace std;

typedef long long ll;
const ll MAX = 1LL << 32;
const int CNT = 1024;
int a[CNT];

struct Node {
    Node* son[2];
    int cnt;
    Node(int _x = 0): cnt(_x) {
        son[0] = son[1] = NULL;
    }
};

void insert(Node* T, int x) {
    for (ll ck = MAX; ck > 0; ck >>= 1) {
        int idx = (x & ck) > 0 ? 1 : 0;
        if (T->son[idx] == NULL) {
            T->son[idx] = new Node();
        }
        ++(T->son[idx]->cnt);
        T = T->son[idx];
    }
}

void remove(Node* T, int x) {
    for (ll ck = MAX; ck > 0; ck >>= 1) {
        int idx = (x & ck) > 0 ? 1 : 0;
        --(T->son[idx]->cnt);
        T = T->son[idx];
    }
}

void clear(Node* T) {
    if (T == NULL) {
        return;
    }
    for (int i = 0; i < 2; ++i) {
        clear(T->son[i]);
    }
    delete T;
}

int gao(Node* T, int x) {
    int res = 0;
    for (ll ck = MAX; ck > 0; ck >>= 1) {
        int idx = (x & ck) > 0 ? 1 : 0;
        res <<= 1;
        if (T->son[idx ^ 1] != NULL && T->son[idx ^ 1]->cnt > 0) {
            T = T->son[idx ^ 1];
            res |= idx ^ 1;
        } else {
            T = T->son[idx];
            res |= idx;
        }
    }
    return res;
}

int main() {
    int T, n;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %d", &n);
        Node* T = new Node();
        for (int i = 0; i < n; ++i) {
            scanf(" %d", a + i);
            insert(T, a[i]);
        }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            remove(T, a[i]);
            for (int j = 0; j < n; ++j) {
                if (j == i) continue;
                remove(T, a[j]);
                int res = gao(T, a[i] + a[j]);
                //printf("remove %d, %d, get %d\n", a[i], a[j], res);
                ans = max(ans, res ^ (a[i] + a[j]));
                //ans = max(ans, gao(T, a[i] + a[j]));
                insert(T, a[j]);
            }
            insert(T, a[i]);
        }
        clear(T);
        printf("%d\n", ans);
    }
    return 0;
}
  • HDU5538 House Building
  • 题意:一坨物体放在地上,求表面积,当然,是放在地上,底面就不算。。。
  • 题解:考虑每个方块的顶面,以及四个侧面即可(如对右侧面,计入的面积应为 max(0,ai,j+1ai,j) ),其中顶面面积恒为1。注意考虑该方块不存在时的情况,此时顶面面积为0。
/* **********************************************

  File Name: 5538.cpp

  Auther: [email protected]

  Created Time: 2015年11月02日 星期一 20时31分00秒

*********************************************** */
#include 
using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int MAX = 64;
int a[MAX][MAX];

int main() {
    int T, n, m;
    scanf(" %d", &T);
    while (T--) {
        scanf(" %d %d", &n, &m);
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                scanf(" %d", &a[i][j]);
            }
        }
        int sum = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (a[i][j] > 0) ++sum;
                sum += max(0, a[i][j] - a[i - 1][j]);
                sum += max(0, a[i][j] - a[i][j - 1]);
                sum += max(0, a[i][j] - a[i + 1][j]);
                sum += max(0, a[i][j] - a[i][j + 1]);
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}

你可能感兴趣的:(套题)