题目链接:https://codeforces.com/gym/102028

B. Ultraman vs. Aodzilla and Bodzilla

题意:

两只怪兽,它们的生命和攻击分别为hpA,hpB,attA,attB,现在你要打败它们,第i回合你的攻击为i。问在承受伤害最少的前提下,攻击序列字典序最小是怎样的。攻击A就是A,攻击B就是B。最后输出承受的最小伤害和攻击序列。

题解:

最后的答案肯定是总回合最小时产生的,但是先打死谁不一定,答案就是两种情况的最小值。之后考虑贪心地构造攻击序列。

这里用了种很巧妙地方法吧,定义溢出伤害为最后一击多余出来的伤害。

我们先考虑先将A打死,然后打B的情况。这种字典序已经尽可能小的,只要保证回合数最小就行了。怎么判断回合数最小呢,设Ra为击败A时的溢出伤害,Rtot为最后一击时的溢出伤害(包含了A溢出的伤害),这里Rtot的计算方法参考代码,如果现在Ra > Rtot,说明如果不要A的溢出伤害,可能会多打一回合,那么这时就应该在某一回合打B,这里的位置我们选择尽可能后面的就是Ra(细节考虑一下)。

另外一种情况,我们就先尽可能地将前面的换成A,最后再来判断Rb和Rtot的关系,如果有Rb > Rtot(注意这里Rb会不断减小,因为我们换了一些操作),那么此时如果没有Rb就要多打一回合,设最后一次操作在第i回合,显然现在Rb < i + 1,直接攻击是攻击不了的。我们此时将最后一次操作撤销,将第i + Rb - Rtot次攻击置为A即可,这样也满足最优(A尽可能靠前并且回合数最小)。

细节可以琢磨一下。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + ;
int T;
ll ha, hb, atta, attb;
ll Get_sum(ll x) {
return 1ll * x * (x + ) / ;
}
ll Get_round(ll x) {
ll ans = ;
while(Get_sum(ans) < x) ans++;
return ans ;
}
int main() {
ios::sync_with_stdio(false) ;cin.tie() ;
cin >> T;
while(T--) {
cin >> ha >> hb >> atta >> attb;
ll ra = Get_round(ha), rb = Get_round(hb), rtot = Get_round(ha + hb);
string res(rtot,'B') ;
ll ans = min(atta * ra + attb * rtot , attb * rb + atta * rtot) ;
if(atta * ra + attb * rtot == ans) {
string cur(rtot,'A') ;
for(int i = ra ; i < rtot ; i++) cur[i] = 'B' ;
ll remain_a = Get_sum(ra) - ha , remain_tot = Get_sum(rtot) - ha - hb ;
if(remain_a > remain_tot) {
cur[remain_a - ] = 'B' ;
}
res = min(res ,cur) ;
}
int last;
if(attb * rb + atta * rtot == ans) {
string cur(rtot,'B') ;
for(int i = rb ; i < rtot; i++) cur[i] = 'A' ;
ll remain_b = Get_sum(rb) - hb;
ll remain = remain_b - Get_sum(rtot) + ha + hb;
for(int i = ; i < ra ; i++) {
if(remain_b >= i + ) {
cur[i] = 'A' ;
remain_b -= i + ;
remain -= i + ;
last = i ;
}
}
if(remain > ) {
cur[last] = 'B';
cur[last + remain] = 'A' ;
}
res = min(res, cur) ;
}
cout << ans << ' ' << res << '\n' ;
}
return ;
}

C. Supreme Command

题意:

有一个n*n的棋盘,现在每一行每一列有一个棋子,位置给出。然后有m次操作,操作包含:

1.L/R/U/D k,将所有的棋子向左/右/上/下全部移动k格;2. ? k,询问第k个棋子现在的坐标; 3. !,询问有多少对棋子在同一个格子上面。

题解:

当有棋子接触边界或者重叠在一起时就永远不会分开了,所以我们可以利用这个信息,如果直接考虑移动棋子,那么很麻烦。所以我们就直接考虑移动上下左右的边界线。

这个题横纵二维可以分开考虑,我们主要考虑水平方向就行。用一个区间[L,R]表示所有的棋子在不超过R-L+1的这个范围中,注意这里的L,R和棋盘上的有所不同,同时维护一个偏移量d就行了。这样我们就可以根据这个偏移量和L,R确定出一个棋子的位置。细节见代码吧。

因为每行每列一开始只有一个棋子,所以如果棋子有重叠,那么最终一定位于[L,R]边界处,每次移动边界时考虑一下当前位置的棋子是否在边界上就行了。最终的询问,分几种情况考虑一下就好了,因为最终的格子可能只有一个,或者一列,一横行,这些答案都是不一样的。

具体细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + ;
int T;
int n, m;
ll LL, LR, RL, RR;
ll C[N] ;
bool vis[N] ;
void cal(int i);
struct sol{
int pos[N], id[N];
ll l, r, d;
void init() {
l = , r = n, d = ;
}
void init_cal() {
cal(id[]), cal(id[n]) ;
}
void setpos(int p, int i) {
pos[i] = p;
id[p] = i;
}
void left(int k) {
while(l < r && l + d - k < ) cal(id[++l]);
if(l + d - k >= ) d -= k;
else d = - l ;
}
void right(int k) {
while(r > l && r + d + k > n) cal(id[--r]);
if(r + d + k <= n) d += k;
else d = n - r;
}
int query(int p) {
if(pos[p] <= l) return l + d;
if(pos[p] >= r) return r + d;
return pos[p] + d;
}
}A, B;
void cal(int i) {
if(vis[i]) return ;
else if(A.pos[i] <= A.l && B.pos[i] <= B.l) vis[i] = , LL++;
else if(A.pos[i] <= A.l && B.pos[i] >= B.r) vis[i] = , LR++;
else if(A.pos[i] >= A.r && B.pos[i] <= B.l) vis[i] = , RL++;
else if(A.pos[i] >= A.r && B.pos[i] >= B.r) vis[i] = , RR++;
}
ll Query() {
if(A.r - A.l > && B.r - B.l > ) return C[LL] + C[RR] + C[LR] + C[RL] ;
if(A.r - A.l == && B.r - B.l > ) return C[LL + RL] + C[LR + RR] ;
if(B.r - B.l == && A.r - A.l > ) return C[LL + LR] + C[RR + RL] ;
return C[LL + LR + RR + RL] ;
}
int main() {
scanf("%d", &T) ;
for(int i = ; i < N ; i++)
C[i] = (ll)(i - ) * i / ;
while(T--) {
scanf("%d%d", &n, &m) ;
for(int i = ; i <= n ; i++) {
int x, y ;
scanf("%d%d", &x, &y) ;
B.setpos(x, i);
A.setpos(y, i);
}
LL = LR = RR = RL = ;
A.init() ; B.init() ;
A.init_cal() ; B.init_cal() ;
int k;
char s[] ;
for(int i = ; i <= m ; i++) {
scanf("%s",s);
if(s[] == '!') cout << Query() << '\n';
else {
scanf("%d", &k) ;
if(s[] == 'L') A.left(k) ;
else if(s[] == 'R') A.right(k) ;
else if(s[] == 'U') B.left(k) ;
else if(s[] == 'D') B.right(k) ;
else cout << B.query(k) << ' ' << A.query(k) << '\n' ;
}
//cout << LL << ' ' << LR << ' ' << RR << ' ' << RL << '\n' ;
}
for(int i = ; i <= n; i++) vis[i] = false;
}
return ;
}

H. Can You Solve the Harder Problem?

题意:

给出n个数,求出所有区间中最大值的和,注意相同序列的区间不重复考虑。

题解:
先不考虑去重的情况,我们可以单独考虑每一个值作为区间最大值时的贡献。这个可以直接用单调栈来维护,但是用单调栈的话不便于去重,所以我们可以考虑线段树。

线段树的做法就是从后往前,依次将每个数插到线段树中,并且做一次区间set,将[i,Ri - 1]这个范围中的数置为ai,然后每次将所有的值累加起来即可。这样位于i位置时考虑了当前数对右边的贡献,对左边的贡献在之后会考虑到:如果在他之前的数比他小的话,那么每次求和也会算上ai对左边区间的贡献。

之后就是去重的问题了,去重我们可以考虑利用height数组,每次减去重复的那段即可。这样可行的原因在于,比如当前这个数height[i] = 4,那么说明他后面的几个数height依次为3,2,1,我们会依次减去,最终当前这个长度为4的序列的贡献我们就不会考虑了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + ;
int tt ;
int n;
int a[N], b[N], d[N], s[N], tmp[N];
int x[N], y[N], sa[N], c[N], height[N], Rank[N], Right[N] ;
void Get_sa(int m) {
n++;
for(int i = ; i < m ; i++) c[i] = ;
for(int i = ; i < n ; i++) c[x[i] = d[i]]++;
for(int i = ; i < m ; i++) c[i] += c[i - ] ;
for(int i = n - ; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n ; k <<= ) {
int p = ;
for(int i = n - k; i < n ; i++) y[p++] = i ;
for(int i = ; i < n ; i++) if(sa[i] >= k) y[p++] =sa[i] - k;
for(int i = ; i < m ; i++) c[i] = ;
for(int i = ; i < n ; i++) c[x[y[i]]]++;
for(int i = ; i < m ; i++) c[i] += c[i - ];
for(int i = n - ; i >= ; i--) sa[--c[x[y[i]]]] = y[i] ;
swap(x , y);p = ;x[sa[]] = ;
for(int i = ; i < n ; i++)
x[sa[i]]=y[sa[i-]]==y[sa[i]]&&y[sa[i-]+k]==y[sa[i]+k]?p-:p++;
if(p >= n) break ;
m = p;
}
n--;
}
void Get_height() {
int k = ;
for(int i = ; i <= n ; i++) Rank[sa[i]] = i ;
for(int i = ; i < n ; i++) {
if(k) k--;
int j = sa[Rank[i] - ];
while(d[i + k] == d[j + k]) k++;
height[Rank[i]] = k ;
}
}
ll T[N << ] , setv[N << ] ;
void build(int o , int l , int r) {
if(l == r) {
T[o] = ;
setv[o] = ;
return ;
}
int mid = (l + r) >> ;
build(o << , l, mid) ;
build(o << | , mid + , r) ;
T[o] = setv[o] = ;
}
void Get_limt() {
int cnt = ;
for(int i = ; i <= n ; i++) {
if(cnt == || d[i] < d[s[cnt]]) {
s[++cnt] = i ;
} else {
while(cnt > && d[i] >= d[s[cnt]])
Right[s[cnt--]] = i;
s[++cnt] = i;
}
}
}
void push_down(int o,int L,int R) {
if(setv[o]) {
T[o] = (R - L + ) * setv[o] ;
setv[o << ] = setv[o << | ] = setv[o] ;
setv[o] = ;
}
}
void push_up(int o, int L, int R) {
int mid = (L + R) >> ;
T[o] = setv[o << ] ? 1ll * setv[o << ] * (mid - L + ) : T[o << ] ;
T[o] += setv[o << | ] ? 1ll * setv[o << | ] * (R - mid) : T[o << |] ;
}
void Set(int o, int L ,int R, int l, int r, int v) {
if(l <= L && R <= r) {
setv[o] = v;
return ;
}
push_down(o, L, R);
int mid = (L + R) >> ;
if(l <= mid) Set(o << , L, mid, l , r, v) ;
if(r > mid) Set(o << | , mid + , R ,l, r ,v) ;
push_up(o, L, R ) ;
}
ll query(int o , int L, int R, int l , int r) {
if(l <= L && R <= r) {
return setv[o] ? setv[o] * (R - L + ) : T[o] ;
}
push_down(o, L, R);
int mid = (L + R) >> ;
ll ans = ;
if(l <= mid) ans += query(o << , L , mid ,l , r) ;
if(r > mid) ans += query(o << | , mid + , R , l , r) ;
return ans ;
}
int main() {
ios::sync_with_stdio(false); cin.tie() ;
cin >> tt;
while(tt--) {
cin >> n ;
for(int i = ; i < n ; i++) cin >> a[i] , b[i] = d[i] = a[i];
sort(b, b + n) ;
int k = unique(b, b + n) - b;
for(int i = ; i < n ; i++) d[i] = lower_bound(b, b + k, d[i]) - b + ;
d[n] = ;
Get_sa(n + ) ;
Get_height() ;
d[n] = n + ;
Get_limt() ;
build(, , n - );
ll res = ;
for(int i = ; i <= n ; i++)
tmp[sa[i]] = height[i] ;
for(int i = n - ; i >= ; i--) {
Set(, , n - , i, Right[i] - , a[i]) ;
res += setv[] ? (n - i) * setv[] : T[] ;
if(tmp[i] > ) res -= query(, , n - , i, i + tmp[i] - ) ;
}
cout << res << '\n' ;
}
return ;
}

2018-2019 ACM-ICPC 焦作赛区 部分题解的更多相关文章

  1. 2018 ACM ICPC 南京赛区 酱油记

    Day 1: 早上6点起床打车去车站,似乎好久没有这么早起床过了,困到不行,在火车上睡啊睡就睡到了南京.南航离南京南站很近,地铁一站就到了,在学校里看到了体验坐直升机的活动,感觉很强.报道完之后去吃了 ...

  2. 华东交通大学2018年ACM“双基”程序设计竞赛部分题解

    链接:https://ac.nowcoder.com/acm/contest/221/C来源:牛客网 C-公式题(2) 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其 ...

  3. 2014 ACM/ICPC 北京邀请赛 部分 题解

    题目链接:http://acm.bnu.edu.cn/bnuoj/problem.php?search=2014+ACM-ICPC+Beijing+Invitational+Programming+C ...

  4. 2014 ACM/ICPC 鞍山赛区现场赛 D&amp;I 解题报告

    鞍山现场赛结束了呢-- 我们出的是D+E+I三道题-- 吾辈AC掉的是D和I两道,趁着还记得.先在这里写一写我写的两道水题D&I的解题报告吧^_^. D题的意思呢是说星云内有一堆排成一条直线的 ...

  5. Substrings 第37届ACM/ICPC 杭州赛区现场赛C题(hdu 4455)

    http://acm.hdu.edu.cn/showproblem.php?pid=4455 https://icpcarchive.ecs.baylor.edu/index.php?option=c ...

  6. 【2017 ACM/ICPC 乌鲁木齐赛区网络赛环境测试赛 E】蒜头君的排序

    [链接]h在这里写链接 [题意] 在这里写题意 [题解] 莫队算法+树状数组. 区间增加1或减少1. 对逆序对的影响是固定的. (用冒泡排序变成升序的交换次数,就是逆序对的个数) [错的次数] 0 [ ...

  7. 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)

    Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai​​(1≤fa ...

  8. 2011 ACM/ICPC 成都赛区(为2013/10/20成都现场赛Fighting)

    hdu 4111  Alice and Bob 博弈:http://www.cnblogs.com/XDJjy/p/3350014.html hdu 4112 Break the Chocolate ...

  9. hdu 4461 第37届ACM/ICPC杭州赛区I题

    题意:给两个人一些棋子,每个棋子有其对应的power,若b没有或者c没有,或者二者都没有,那么他的total power就会减1,total power最少是1,求最后谁能赢 如果b或c出现的话,fl ...

随机推荐

  1. 【springmvc+mybatis项目实战】杰信商贸-7.生产厂家新增

    我们要实现新的功能,就是生产厂家的新增先来回顾一下系统架构图我们数据库这边已经建好表了,接下来要做的就是mapper映射 编辑FactoryMapper.xml文件,加入“添加”的逻辑配置代码块 &l ...

  2. ntp时钟服务器配置

    集群中时间不同步有可能会让大数据的应用程序运行混乱,造成不可预知的问题,比如Hbase,当时间差别过大时就会挂掉,所以在大数据集群中,ntp服务,应该作为一种基础的服务,以下在演示在CentOS 7. ...

  3. scrum立会报告+燃尽图(第二周第四次)

    此作业要求参考: https://edu.cnblogs.com/campus/nenu/2018fall/homework/2249 一.小组介绍 组名:杨老师粉丝群 组长:乔静玉 组员:吴奕瑶.公 ...

  4. 总结在Visual Studio Code运行node.js项目遇到的问题

    一.cannot find module “lodash” 项目运行时出现以下错误: Error: Cannot find module 'lodash' at Function.Module._re ...

  5. 寒假MOOC学习计划

    我选择的是西北工业大学的课程,理由如下: 首先,选择这门课的网友还蛮多的,特意看了一下评价,也不错: 其次,这个课程的排版与我从图书馆借来的一本书内容排版比较符合,可以结合起来一起看,说不定会有更多收 ...

  6. C语言的知识与能力予以自评

    看到一个问卷不错,拟作为第三次作业的部分内容. 你对自己的未来有什么规划?做了哪些准备?答:多学习几门生存技巧,首先先学会碰壁. 你认为什么是学习?学习有什么用?现在学习动力如何?为什么?答:学习是人 ...

  7. timestamp 学习

    该答案摘抄自CSDN. 哇,奇迹,跨度三年了,不知道楼主是否已经解决了此问题. 路过,简单说一下,timestamp 主要是记录该行的最后修改时间戳, 注意,这个时间戳是不可以转换为时间的,只能标注该 ...

  8. Android工程方法数超过64k,The number of method references in a .dex file cannot exceed 64K.

    最近将一个老的Eclipse项目转到Android Studio后,用gradle添加了几个依赖,项目可以make,但是一旦run就报错 Error:The number of method refe ...

  9. lintcode-129-重哈希

    129-重哈希 哈希表容量的大小在一开始是不确定的.如果哈希表存储的元素太多(如超过容量的十分之一),我们应该将哈希表容量扩大一倍,并将所有的哈希值重新安排.假设你有如下一哈希表: size=3, c ...

  10. 【leetcode】198.HouseRobber

    198.HouseRobber You are a professional robber planning to rob houses along a street. Each house has ...