1. 程式人生 > >【套題】2015ACM/ICPC亞洲區長春站 HDU5532 5533 5534 5536 5538

【套題】2015ACM/ICPC亞洲區長春站 HDU5532 5533 5534 5536 5538

  • 水幾個題,熟悉一下鍵盤。。。
  • HDU5532AlmostSortedArray
  • 題意:ASA定義為,僅去掉一個(OneandOnlyOne)元素後陣列是非降序或者非升序。
  • 題解:很明顯,判斷一個序列是否有序可以通過判斷其LongestNonDecreasingSubsquence或者LongestNonIncreasingSubsquence是否等於序列長度來得到。
/* **********************************************

    File Name: test.cpp

    Auther: [email protected]

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

*********************************************** */
#include <bits/stdc++.h> 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; }
  • HDU5233DancingStarsonMe
  • 題意:求一堆點是否構成一個正n邊形
  • 題解:求凸包,判斷一下
    • 凸包頂點個數是否為n
    • 凸包所有邊是否等長
/* **********************************************

  File Name: 5533.cpp

  Auther: [email protected]

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

*********************************************** */
#include <bits/stdc++.h>
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;
}
  • HDU5534PartialTree
  • 題意: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: zhengd[email protected]

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

*********************************************** */
#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> P;

const int INF = 0xfffffff;
const int MAX = 2018;
vector<P> 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;
}