CF Edu125 Div.2
A - Integer Moves(思维)
Description:
给定一个坐标x y 从0 0开始走 每次走的欧几里得距离必须是整数 问几步能到
Solution
0 0到0 0 0步
如果是直角三角形 就可以一步到
如果不是直角三角形 那就先走一步横再走一步竖 两步到
Code:
void solve()
{
int x, y;
cin >> x >> y;
if(x == 0 && y == 0) {cout << 0 << endl; return;}
if((int)sqrt(x * x + y * y) * (int)sqrt(x * x + y * y) == x * x + y * y)
cout << 1 << endl;
else
cout << 2 << endl;
}
B - XY Sequence(贪心)
Description:
给定n b x y 要求构造出一个长度为n+1 和最大的序列
构造规则 序列首位为0 下一位可以选择前一位+x 或者 -y 但是不能大于b
Solution
贪心 +x小于等于b就加 不行就-y
证明的话 我们可以想到 只对第一个能+x的地方-y 后面正常操作 那么折线将会整体低一节 那还是加+x比较合适
Code:
void solve()
{
LL n, b, x, y;
cin >> n >> b >> x >> y;
LL res = 0, cur = 0;
for(int i = 0; i < n; i++)
{
if(cur + x <= b) cur += x, res += cur;
else cur -= y, res += cur;
}
cout << res << '\n';
}
C - Bracket Sequence Deletion(读题 + 分类讨论)
Description:
操作
每次操作选择一个最短的好前缀并将其删去
定义一个好前缀
该前缀是一个合法的括号序列 eg () (()) ((())())
或者该前缀是一个长度大于等于2的回文串
你可以进行任意次操作直到序列中不存在好前缀为止
输出操作次数和剩下的序列的长度
Solution
分类讨论
用指针l表示当前序列的首位 用l的前进 来等价于 删去前缀
当前为'('的时候 后面无论是')'或者'(' 这都是一个最短前缀 所以l无脑加2即可
当前为')'的时候 找下一个')' 因为"))"或者")(()" 得出无论 两个)中间夹着多少个( 都是回文串
什么时候终止呢 当且仅当 当前为)且找不到下一个)时终止
Code:
void solve()
{
int n;
string s;
cin >> n >> s;
int l = 0, cnt = 0;
while(l + 1 < n)
{
if(s[l] == '(' || (s[l] == ')' && s[l + 1] == ')'))
l += 2;
else //s[l] == ')'
{
int r = l + 1;
while(r < n && s[r] != ')') r ++;
if(r == n) break;
l = r + 1;
}
cnt ++;
}
cout << cnt << ' ' << n - l << endl;
}
D - For Gamers. By Gamers.(预处理 + 二分)
Description:
给定n个单位 和 C个金币
然后你会得到各个单位的费用c_i和攻防属性d_i h_i
以及下面的怪物攻防属性 D H
有m个怪物 你只能雇佣n个同一单位去击杀怪物 保证每一个单位都存活的情况下杀掉怪物
求杀掉每个怪物的最小花费 若金币不够的话就输出-1
Solution
先要推一下式子 什么叫保证每一个单位都存活的情况下杀掉怪物
原句为
Thus, Monocarp wins the battle if and only if his squad kills the monster strictly faster than the monster kills one of his units. The time is compared with no rounding.
翻译: 因此,当且仅当他的小队杀死怪物的速度严格快于怪物杀死他的一个单位时,Monocarp才会赢得这场战斗。时间的比较是没有四舍五入的(double)
如果存在多个单位的话 可以交替抗伤害 所以我们试一下推公式
怪物杀单位的时间 h/D 单位杀怪物的时间 H/d
当且仅当 h/D > H/d成立时 能够赢
设我们放了x个单位 那么(h/D > H/d*x) x > HD / hd ==> x = floor(HD/hd) + 1;
cost = x*c_i
好的 思路整理出来了 那我们可以做到的是 对于每个怪物枚举一遍每种单位打怪的花费 取最小花费
这样就是n * m 铁铁超时
那从哪里优化呢 想一想有哪些参数 1单位2怪物3花费 那么不能枚举12 那就枚举32试试
预处理出1~C的每个花费得到的最大战斗属性 然后对每个怪物进行二分查找 找出第一个刚好杀掉怪物的花费
如果找不到 那就证明花费爆了
Code:
LL f[N];
int main()
{
int n, C;
scanf("%d%d", &n, &C);
for(int i = 1; i <= n; i++)
{
LL c, d, h;
scanf("%lld%lld%lld", &c, &d, &h);
f[c] = max(f[c], d * h);
//爆了c个金币 得到一个单位 为了防止同样费用的单位 取max
}
for(int i = 1; i <= C; i++)
{
if(f[i])
{
for(int j = i; j <= C; j += i) //枚举i的倍数j
f[j] = max(f[j], f[i] * j / i); //状态转移 爆j个金币 得到j / i个单位
}
}
for(int i = 1; i <= C; i++) f[i] = max(f[i], f[i - 1]);
//得到当前金币数能得到的最强的战斗属性
int m;
scanf("%d", &m);
while(m --)
{
LL x, y;
scanf("%lld%lld", &x, &y);
x *= y;
LL l = 1, r = C;
while(l < r)
{
int mid = l + r >> 1;
if(f[mid] > x) r = mid;
else l = mid + 1;
}
if(f[l] > x) printf("%lld ", l);
//二分出刚好可以打过这个怪物的最小花费 也就是第一个大于怪物属性的单位
else printf("-1 ");
}
return 0;
}