14048: 【原4048】Evensgn的坚定之桌
题目
题目描述
author: Evensgn 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4048
题目描述
Evensgn
这张桌子一共有 \(n\) 条腿,第 \(i\) 条腿的长度为 \(l_i\)。
Evensgn 决定拆除这张桌子的一些桌腿来使它变得稳定。对于每条桌腿,Evensgn 已经预判出了 \(d_i\) ——拆除第 \(i\) 条桌腿所需要花费的时间。
众所周知,有这样一句古老的谚语,“一张有 \(k\) 条腿的桌子被称作是 稳定的,当且仅当它有 多于一半数量 的桌腿是最大长度的。”
例如,如果一张有 \(5\) 条桌腿的桌子是稳定的,那么它的 \(5\) 条桌腿中至少有 \(3\) 条桌腿是最大长度的。又例如,一张只有 \(1\) 条桌腿的桌子总是稳定的,而一张有 \(2\) 条桌腿的桌子是稳定的当且仅当这两条桌腿是相同长度的。
Evensgn 想要留出时间看 《逃避虽可耻但有用》 里的 gakki ,因此他希望在最少的时间内将这张桌子变成 稳定的。他找到了你,请你帮忙计算他所需要花费的最少时间是多少。
输入格式
- 第一行为一个整数 \(n\) ,表示 Evensgn 的新桌原先的桌腿数量。
- 接下来一行为 \(n\) 个整数 \(l_i\),\(l_i\) 表示第 \(i\) 条桌腿的长度。
- 接下来一行为 \(n\) 个整数 \(d_i\),\(d_i\) 表示 Evensgn 拆除第 \(i\) 条桌腿所需要花费的时间。
输出格式
输出一个整数,Evensgn 将新桌变成 稳定的 所需要花费的最少时间。
输入输出样例
不知为何,这道题目的样例数量竟然达到了惊人的 \(3\) 组。
样例输入1
2
1 5
3 2
样例输出1
2
样例输入2
3
2 4 4
1 1 1
样例输出2
0
样例输入3
6
2 2 1 1 3 3
4 3 5 5 2 1
样例输出3
8
数据规模
- 对于 \(30\%\) 的数据,\(1 \leq n \leq 100, 1 \leq l_i \leq 10^5, 1 \leq d_i \leq 200\)。
- 对于 \(70\%\) 的数据,\(1 \leq n \leq 1000, 1 \leq l_i \leq 10^5, 1 \leq d_i \leq 200\)。
- 对于 \(100\%\) 的数据,\(1 \leq n \leq 10^5, 1 \leq l_i \leq 10^5, 1 \leq d_i \leq 200\)。
FineArtz's solution
/* Evensgn的坚定之桌 */
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
class Leg{
public:
int d = 0, l = 0;
};
bool cmp(Leg l1, Leg l2){
return (l1.l < l2.l || (l1.l == l2.l && l1.d < l2.d));
}
/*bool cmp2(Leg l1, Leg l2){
return (l1.d < l2.d);
}*/
Leg leg[100005];
int f[100005], d[205];
int n;
int main(){
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> leg[i].l;
for (int i = 1; i <= n; ++i)
cin >> leg[i].d;
sort(leg + 1, leg + n + 1, cmp);
f[1] = 0;
int nowl = 1;
for (int i = 2; i <= n; ++i){
if (leg[i].l == leg[i - 1].l) ++nowl;
else{
for (int k = i - 1; k >= i - nowl; --k)
++d[leg[k].d];
nowl = 1;
}
if (nowl > i / 2) f[i] = 0;
else{
int tmp1 = f[i - 1] + leg[i].d;
int tmp2 = 0, cnt = 0, lim = i - 2 * nowl + 1;
for (int k = 0; k <= 200; ++k){
if (cnt + d[k] >= lim){
tmp2 += k * (lim - cnt);
break;
}
else{
tmp2 += k * d[k];
cnt += d[k];
}
}
f[i] = min(tmp1, tmp2);
}
}
cout << f[n] << endl;
return 0;
}
ligongzzz's solution
#include "iostream"
#include "cstdio"
#include "cstring"
#include "cmath"
using namespace std;
template <class T>
class mVector {
T** vector_data = nullptr;
unsigned int size = 0;
unsigned int capacity = 0;
public:
//构造函数
mVector() = default;
mVector(unsigned int _size) :size(_size) {
capacity = _size * 2;
vector_data = new T * [capacity] {nullptr};
}
mVector(unsigned int _size, const T& val) :size(_size) {
capacity = _size * 2;
vector_data = new T * [capacity] {nullptr};
for (unsigned int i = 0; i < _size; ++i)
vector_data[i] = new T(val);
}
mVector(const mVector<T> & _vector) :size(_vector.size), capacity(_vector.capacity) {
vector_data = new T * [capacity] {nullptr};
for (int i = 0; i < size; ++i)
vector_data[i] = new T(*_vector.vector_data[i]);
}
//析构函数
~mVector() {
for (unsigned int i = 0; i < size; ++i)
delete vector_data[i];
delete[] vector_data;
}
//迭代器
class iterator {
T** pos = nullptr;
friend iterator mVector<T>::begin();
friend iterator mVector<T>::end();
friend void mVector<T>::erase(const iterator& val);
public:
iterator() = default;
iterator(const iterator& other) {
pos = other.pos;
}
iterator& operator++() {
++pos;
return *this;
}
iterator operator++(int) {
iterator temp(*this);
++pos;
return temp;
}
iterator& operator--() {
--pos;
return *this;
}
iterator operator--(int) {
iterator temp(*this);
--pos;
return temp;
}
bool operator==(const iterator& other) const {
return pos == other.pos;
}
bool operator!=(const iterator& other) const {
return pos != other.pos;
}
iterator& operator=(const iterator& other) {
pos = other.pos;
return *this;
}
T& operator*() const {
return **pos;
}
};
//反向迭代器
template <class U>
class reverse_iterator {
U val;
friend reverse_iterator<U> mVector<T>::rbegin();
friend reverse_iterator<U> mVector<T>::rend();
public:
U& base() {
return val;
}
reverse_iterator() = default;
reverse_iterator(const reverse_iterator<U>& other) {
val = other.val;
}
reverse_iterator(const U& other) {
val = other;
}
reverse_iterator<U>& operator++() {
--val;
return *this;
}
reverse_iterator<U> operator++(int) {
reverse_iterator<U> temp(*this);
--val;
return temp;
}
reverse_iterator<U>& operator--() {
++val;
return *this;
}
reverse_iterator<U> operator--(int) {
reverse_iterator<U> temp(*this);
++val;
return temp;
}
bool operator==(const reverse_iterator<U>& other) const {
return val == other.val;
}
bool operator!=(const reverse_iterator<U>& other) const {
return val != other.val;
}
reverse_iterator<U>& operator=(const reverse_iterator<U>& other) {
val = other.val;
return *this;
}
T& operator*() const {
return *val;
}
};
reverse_iterator<iterator> rbegin() {
auto temp = end();
--temp;
reverse_iterator<iterator> result;
result.val = temp;
return result;
}
reverse_iterator<iterator> rend() {
auto temp = begin();
--temp;
reverse_iterator<iterator> result;
result.val = temp;
return result;
}
//增加元素
void push_back(const T & val) {
if (size < capacity)
vector_data[size++] = new T(val);
else {
T** temp_data = new T * [(capacity + 1) * 2]{ nullptr };
for (unsigned int i = 0; i < size; ++i)
temp_data[i] = vector_data[i];
temp_data[size++] = new T(val);
capacity = (capacity + 1) * 2;
delete[] vector_data;
vector_data = temp_data;
}
}
//删除末尾
void pop_back() {
delete vector_data[--size];
vector_data[size] = nullptr;
}
//清空
void clear() {
for (unsigned int i = 0; i < size; ++i) {
delete vector_data[i];
vector_data[i] = nullptr;
}
size = 0;
}
//删除
void erase(const iterator & val) {
delete* val.pos;
for (auto p = val.pos; p != vector_data + size - 1; ++p)
* p = *(p + 1);
--size;
vector_data[size] = nullptr;
}
size_t get_size() {
return size;
}
//重载运算符
T & operator[](const unsigned int& pos) {
return *vector_data[pos];
}
iterator begin() {
iterator temp;
temp.pos = vector_data;
return temp;
}
iterator end() {
iterator temp;
temp.pos = vector_data + size;
return temp;
}
};
class leg {
public:
int length = 0,
times = 0;
};
leg table[100009];
int houzhui[100009] = { 0 };
int time_sum[209] = { 0 };
mVector<int> length_sum[100009];
int main() {
int n;
int max_length = 0;
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d", &table[i].length);
for (int i = 0; i < n; ++i)
scanf("%d", &table[i].times);
for (int i = 0; i < n; ++i) {
length_sum[table[i].length].push_back(table[i].times);
max_length = table[i].length > max_length ? table[i].length : max_length;
}
//计算后缀和
for (int i = 100005; i >= 0; --i) {
houzhui[i] = houzhui[i + 1];
for (int j = 0; j < length_sum[i].get_size(); ++j)
houzhui[i] += length_sum[i][j];
}
int ans = int(1e9 + 7);
//遍历计算
for (int i = 1, cur_remain = 0; i <= max_length; ++i) {
if (length_sum[i].get_size() == 0)
continue;
int temp = houzhui[i + 1];
//计算桶内的剩余
for (int remain = cur_remain, pos = 0, step = 0;
remain >= length_sum[i].get_size(); --remain) {
if (time_sum[pos] <= step) {
for (++pos; time_sum[pos] == 0; ++pos);
step = 0;
}
temp += pos;
++step;
}
ans = temp < ans ? temp : ans;
//将当前长度入桶
for (int j=0;j<length_sum[i].get_size();++j)
++time_sum[length_sum[i][j]];
cur_remain += length_sum[i].get_size();
}
cout << ans;
return 0;
}