您的位置:首页 > 其它

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

2015-11-07 17:55 585 查看
水几个题,熟悉一下键盘。。。

HDU5532 Almost Sorted ArrayHDU5532\ Almost\ Sorted\ Array

题意:ASAASA定义为,仅去掉一个(One and Only OneOne\ and\ Only\ One)元素后数组是非降序或者非升序。

题解:很明显,判断一个序列是否有序可以通过判断其Longest NonDecreasing SubsquenceLongest\ NonDecreasing\ Subsquence或者Longest NonIncreasing SubsquenceLongest\ NonIncreasing\ Subsquence是否等于序列长度来得到。

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

File Name: test.cpp

Auther: zhengdongjian@tju.edu.cn

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


HDU5233 Dancing Stars on MeHDU5233\ Dancing\ Stars\ on\ Me

题意:求一堆点是否构成一个正nn边形

题解:求凸包,判断一下→\to

凸包顶点个数是否为nn

凸包所有边是否等长

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

File Name: 5533.cpp

Auther: zhengdongjian@tju.edu.cn

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


HDU5534 Partial TreeHDU5534\ Partial\ Tree

题意:nn个点连成一棵树,对某个顶点vv,若其度为degv{deg}_{v},则价值为fdegvf_{{deg}_{v}}

题解:nn个点,n−1n-1条边,共有2∗n−22*n-2个度需要分配。可以证明,首先对每个顶点赋一个度,将剩余的n−2n-2个度任意分配给剩下的顶点,均可以得到一棵树。我们可以简单地反证一下~

对每个顶点,最少可能分配到11个度,最多可能分配到1+(n−2)=n−11+(n-2)=n-1个度,这是满足任意一个顶点的度的限制条件1≤degv≤n−11\le {deg}_{v}\le {n-1}的。

2∗n−22*n-2个度分配完后,我们可以开始两两顶点连边,每连一条边,二者的度分别减11,先不考虑是否会造成环,那么

① 当仅剩22个度时,将对应的两个点连一条边,即完成连边

② 当多余22个度时,假设剩余kk个度,只需要任意选择两个度还没用完的点连接起来,就可以达到度剩余k−2k-2的局面

由①②可知, 恰好可以连出2∗n−22=n−1{{2*n-2}\over{2}}={n-1}条边。此时,根据我们开始的分配,没有任何一个点是没有连至少一条边的,于是不可能存在孤立顶点;另外,,,,窝好像不能证明整个图的连通性鸭(;′⌒`)。。。

于是可以换一个方向考虑,窝们考虑一个放射形图案,一个点度为n−1n-1,作为根,其他所有点都是它的孩子,此时为1+1+⋯+(n−1)1+1+\dots +\left(n-1\right)的组合,将一个点拿下,连到其它点上,变成1+1+⋯+2+(n−2)1+1+\dots+2+\left(n-2\right)的组合,相当于最后的n−2n-2个度分了11个出去,如此下去,可以达到将n−2n-2分解的任何一种组合。

题解续:做完上述分析,我们就可以先考虑一个简化版本了。容量为n−2n-2的背包,有n−1n-1件物品,分别为大小为ii,价值为fif_i,有无限多个,问装满背包最大获得价值为多少。

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

File Name: 5534.cpp

Auther: zhengdongjian@tju.edu.cn

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


HDU5536 Chip FactoryHDU5536\ Chip\ Factory

题意:问最大的(si+sj)⊕sk\left({s_i}+{s_j}\right) \oplus {s_k}

题解:将所有数归一化为32 bit32\ bit的串,建立TrieTrie树求解即可。复杂度log(n2)∗nlog(n^2)*n

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

File Name: 5536.cpp

Auther: zhengdongjian@tju.edu.cn

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

*********************************************** */
#include <bits/stdc++.h>
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 BuildingHDU5538\ House\ Building

题意:一坨物体放在地上,求表面积,当然,是放在地上,底面就不算。。。

题解:考虑每个方块的顶面,以及四个侧面即可(如对右侧面,计入的面积应为max(0,ai,j+1−ai,j)max(0, a_{i,{j+1}}-a_{i,j})),其中顶面面积恒为1。注意考虑该方块不存在时的情况,此时顶面面积为0。

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

File Name: 5538.cpp

Auther: zhengdongjian@tju.edu.cn

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

*********************************************** */
#include <bits/stdc++.h>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: