战斗爽
思路:
首先我们要处理攻击敌人的顺序问题,优先级最高的为血量,之后依次为攻击力和敌人编号
注意同一敌人最多收到k次攻击,这里也需要记录被攻击次数
这里我们可以通过重载优先队列来实现
struct all{
int at, hp, pos, sk;
};
struct cmp{
bool operator() (const all a, const all b) {
if (a.hp == b.hp && a.at == b.at) return a.pos > b.pos;
else if (a.hp == b.hp) return a.at > b.at;
return a.hp > b.hp;
}
};
小华每回合都会收到当前攻击力最强的敌人的伤害,需要Ologn以内的方式定向查找和删除当前击杀的敌人
这里我们选择可重复的multiset
multiset<int> se;
auto it = se.find(a);
if (it != se.end()) se.erase(it);
特别注意,取当前最大攻击元素时的两种取法
auto it = se.rbegin();
auto it = (--se.end());
AC code :
struct all{
int at, hp, pos, sk;
};
struct cmp{
bool operator() (const all a, const all b) {
if (a.hp == b.hp && a.at == b.at) return a.pos > b.pos;
else if (a.hp == b.hp) return a.at > b.at;
return a.hp > b.hp;
}
};
void solve() {
int n, u, k, hq; cin >> n >> u >> k >> hq;
priority_queue<all, vector<all>, cmp> pq;
int sum = 0, ans = 0;
multiset<int> se;
for (int i = 1; i <= n; i ++) {
int a, h; cin >> a >> h;
se.insert(a);
pq.push({a, h, i, 0});
}
while (!pq.empty() && hq > 0) {
auto [a, h, p, s] = pq.top();
pq.pop();
if (s == k) continue;
int ca = h - u / (!s ? 1 : 2);
s ++;
if (ca > 0) {
pq.push({a, ca, p, s});
} else {
ans ++;
auto it = se.find(a);
if (it != se.end()) se.erase(it);
}
if (!se.empty()) {
auto it = --se.end();
hq -= *it;
}
}
cout << ans << endl;
}
持家
思路:
很显然先用打折券再用减免券((⊙o⊙)…)
前缀和和前缀积分别处理一下打折券和减免券
枚举用0~k张打折券,其余用减免券的情况,并取最小值即可
特别注意枚举过程中可能会出现其中一种券不足的情况
AC code:
void solve() {
int p, n, k; cin >> p >> n >> k;
vector<int> da;
vector<int> jian;
for (int i = 0; i < n; i ++) {
int t, p; cin >> t >> p;
if (t) jian.push_back(p);
else da.push_back(p);
}
sort(da.begin(), da.end());
sort(jian.begin(), jian.end(), greater<int>());
vector<double> sda;
double st = 1;
for (int i = 0; i < da.size(); i ++) {
st *= 1.0 * da[i] / 10;
//cout << st << ' ';
sda.push_back(st);
}
int o = 0;
vector<int> sji;
for (int i = 0; i < jian.size(); i ++) {
o += jian[i];
sji.push_back(o);
}
double ans = p;
for (int i = 0; i <= k; i ++) {
double ca = p, cb = 0;
if (!sda.empty() && i > 0) {
if (i <= sda.size()) ca = p * sda[i - 1];
else ca = p * sda.back();
}
int j = k - i;
if (!sji.empty() && j > 0) {
if (j <= sji.size()) cb = sji[j - 1];
else cb = sji.back();
}
ans = min(ans, max(0.0, ca - cb));
}
printf("%.2lf\n", ans);
}
进步
思路:
其实主要就是修改操作如何在满足时间复杂度的情况下修改一个后缀的前缀和
用树状数组或者线段树都可以
AC code:
void update(int x, int val) {
for (; x <= n; x += x & -x)
bit[x] += val;
}
int query(int x) {
int res = 0;
for (; x; x -= x & -x)
res += bit[x];
return res;
}
void solve() {
cin >> n >> q;
for (int i = 1; i <= n; i ++)
cin >> a[i], bit[i] = 0;
for (int i = 1; i <= n; i++)
update(i, a[i]);
int op, x, y, cnt = 0;
int ans = 0;
for (int i = 1; i <= q; i ++) {
cin >> op >> x >> y;
if (op == 1) {
int de = y - a[x];
a[x] = y;
update(x, de);
} else {
cnt++;
int sr = query(y), sl = query(x - 1);
int res = sr / 100 - sl / 100;
ans ^= (res * cnt);
}
}
cout << ans << endl;
}
制衡
思路:
dp
AC code:
void solve() {
int n, k;
cin >> n >> k;
for (int i = 0; i <= k + 10; i ++) dp[i] = 0;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= k; j ++) {
cin >> a[j];
}
st[0] = 0;
for (int j = 1; j <= k; j ++) {
st[j] = max(st[j - 1], dp[j]);
}
for (int j = 1; j <= k; j ++) {
dp[j] = st[j] + a[j];
}
}
cout << *max_element(dp + 1, dp + k + 1) << endl;
}