链接:2182 -- Lost Cowshttp://poj.org/problem?id=2182
纯暴力:
#include <iostream>
#define x first
#define y second
using namespace std;
typedef long long ll;
const int N = 8004;
int ans[N], a[N], pre[N];
int main() {
// system("chcp 65001");
cin.tie(0);
cout.tie(0);
freopen("C:/Users/zhaochen/Desktop/input.txt", "r", stdin);
int n;
cin >> n;
a[1] = 1;
for (int i = 2; i <= n; i++) {
a[i] = i;
cin >> pre[i];
}
for (int i = n; i > 0; i--) {
int res = 0;
for (int j = 1; j <= n; j++) {
if (a[j] != -1) {
res++;
if (res == pre[i] + 1) {
ans[i] = a[j];
a[j] = -1;
break;
}
}
}
}
for (int i = 1;i <= n;i++) {
cout << ans[i] << endl;
}
return 0;
}
线段树:
#include <iostream>
#define x first
#define y second
using namespace std;
typedef long long ll;
const int N = 8004;
int ans[N], pre[N];
struct {
int l, r, len;
} tree[4 * N];
void BuildTree(int left, int right, int root) { // 构建树根root
tree[root].l = left; // 左边界
tree[root].r = right; // 右边界
tree[root].len = right - left + 1; // len存这个区间的数字个数,即这个结点下的数量
if (left == right) {
return;
}
int mid = (left + right) >> 1;
int lchild = root << 1;
BuildTree(left, mid, lchild); // 构建左子树根root*2
BuildTree(mid + 1, right, lchild + 1); // 构建右子树根root*2+1
}
int find(int root, int num) { // 从树根root开始,找到第num个元素
tree[root].len--; // 把此次更新的区间长度-1
if (tree[root].l == tree[root].r) {
return tree[root].l;
}
int lchild = root << 1;
// 如果左子区间内的个数不够,则查询右子区间中第num - tree[lchild].len个元素
if (tree[lchild].len < num) {
return find(lchild + 1, num - tree[lchild].len);
}
// 查询左子区间中第num个元素
return find(lchild, num);
}
int main() {
// system("chcp 65001");
cin.tie(0);
cout.tie(0);
freopen("C:/Users/zhaochen/Desktop/input.txt", "r", stdin);
int n;
cin >> n;
for (int i = 2; i <= n; i++) {
cin >> pre[i]; // 排在第i个前的有pre[i]个
}
BuildTree(1, n, 1);
for (int i = n; i > 0; i--) {
ans[i] = find(1, pre[i] + 1); // 第i个排在pre[i]+1
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << endl;
}
return 0;
}
树状数组图解:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#define x first
#define y second
using namespace std;
typedef long long ll;
const int N = 8004;
int n;
int node[N] = { 0 }, precede[N] = { 0 }, ans[N] = { 0 };
// 树状数组巧妙地将数组不断按2的次方长度拆分,使得修改和求和都能在O(logn)的复杂度内完成
int lowbit(int x) { // 返回x的二进制数的最后一个1代表的大小,利用负数的补码(原码取反+1)
return x & (-x);
}
// 块i与第一个包含他本身的块正好差lowbit(i),相加就可得到下一个需要更新的块
void add(int i, int value) { // 操作a[i]+value,更新和a[i]有关的node[]
while (i <= n) { // 更新到最大的块
node[i] += value;
i += lowbit(i);
}
}
int sum(int i) { // 求和操作,sum=a[1]+...+a[i],本题sum[i]代表i在当前的大小排位
int sum = 0;
while (i > 0) {
sum += node[i];
i -= lowbit(i);
}
return sum;
}
int findpos(int x) { // 二分法寻找sum(pos) = precede[i] + 1 对应的pos
int left = 1, right = n;
while (left < right) { // 找第一个<=x的sum(pos)对应的pos
int mid = (left + right) >> 1;
if (sum(mid) < x) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
int main() {
// system("chcp 65001");
cin.tie(0);
cout.tie(0);
freopen("C:/Users/zhaochen/Desktop/input.txt", "r", stdin);
cin >> n;
for (int i = 2; i <= n; i++) {
cin >> precede[i]; // 排在第i个前的有precede[i]个
}
for (int i = 1; i <= n; i++) {
node[i] = lowbit(i); // 本题特殊,无需用add()初始化node[],因为最初sum(i)为i
}
for (int i = n; i > 0; i--) {
// 找剩下的第precede[i] + 1大的数
int pos = findpos(precede[i] + 1);
add(pos, -1); // 和a[pos]有关的node[]记录的长度-1
ans[i] = pos;
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << endl;
}
return 0;
}