Codeforces Round #666 (Div. 1)
A. Multiples of Length (CF 1396 A)
题目大意
给定一个个数字的数组,你需要进行三次操作。
每次操作,选择一个区间,然后对区间里的每一个数,加上一个该区间长度的倍数。不同数加的数可以不同。
输出三次操作的区间以及该区间每个数所加的数。
可以证明保证有解。
解题思路
构造题。为应对任意数字的情况,我们让每个的系数变为。
如果,那么答案就是
否则就
神奇的代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int k; cin >> k; vector<LL> qwq; int n = k; while(k--){ LL a; cin>>a; qwq.push_back(a); } if (n == 1){ cout<<"1 1"<<endl; cout<<-qwq[0]<<endl; cout<<"1 1"<<endl; cout<<'0'<<endl; cout<<"1 1"<<endl; cout<<'0'<<endl; return 0; } cout<<"1 1"<<endl; cout<<-qwq[0]<<endl; cout<<"1 "<<n<<endl; qwq[0] = 0; for(size_t i = 0; i < qwq.size(); ++ i) cout<<-(LL)n*qwq[i]<<(i == qwq.size() - 1?'\n':' '); cout<<"2 "<<n<<endl; for(size_t i = 1; i < qwq.size(); ++ i) cout<<(LL)(n-1)*qwq[i]<<(i == qwq.size() - 1?'\n':' '); return 0; }
B. Stoned Game (CF 1396 B)
题目大意
初始堆石子,和轮流拿,先。一个人不能拿上一轮对方拿的那堆石子。当两者均采取最优策略的情况下,谁必赢。
解题思路
博弈题。
很显然,时赢。
时,若两堆石子数相同,则赢,否则赢。
其余的,他们采取最优策略,即总是拿石子数最多的那堆,模拟即可得到答案。
或者可以这样考虑,因为最后是剩下两堆石子的,而如果两堆石头数量相同,则赢。那么,我们假设最后剩下的是第堆和第堆,初始,为了赢,需要花轮,使得这两堆相同,剩下的取其他堆,只要此时剩下的其他堆的数量是偶数,那么最后的局面就进入必赢局面。
也即是偶数,那么必赢。
由于时偶数,不改变结果的奇偶性,所以判断的奇偶性即可。
特别的,如果最大堆的数量大于其他堆数量的和,则必赢。
综上,如果最大堆的数量大于其他堆数量的和或是奇数,则必赢,否则必赢。
神奇的代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int kase; read(kase); for (int ii = 1; ii <= kase; ii++) { int n; read(n); int tot = 0; vector<int> qwq(n); for(int i = 0; i < n; ++ i){ read(qwq[i]); tot += qwq[i]; } sort(qwq.begin(),qwq.end()); if (n == 1) puts("T"); else if (n == 2){ if (qwq[0] == qwq[1]) puts("HL"); else puts("T"); } else { tot -= qwq[qwq.size() - 1]; if (qwq[qwq.size() - 1] > tot) puts("T"); else{ tot -= qwq[qwq.size() - 1]; if (tot & 1) puts("T"); else puts("HL"); } } } return 0; }
C. Monster Invaders (CF 1396 C)
题目大意
有个关卡,初始第一个关卡,第个关卡有个的普通怪物和个的怪物。
你有三种枪:
- 手枪,对一只怪物造成伤害,花费时间
- 激光枪,对所有怪物造成伤害,花费时间
- AWP,直接干掉一只怪物,花费时间
除了第二种,其余枪要在干掉该关卡的普通小怪后才能对造成伤害。且如果对造成伤害,且未死时,必须转移到上一个或下一个关卡。当然,干掉完当前关卡的怪物需要手动转移到下一个关卡。
转移关卡花费时间。
问干掉需要的最短时间。
数据保证。
解题思路
干掉一个关卡的所有怪物,我们有三种方法。
- 手枪+AWP
- 激光枪+手枪
- 手枪+手枪
第一种很简单,干完该关卡boss后就跳到下一个关卡。
关键就是第二个和第三个,它会跳到其他关卡,然后再跳回来。问题就是会往哪跳,跳多远。
首先任何往后跳的都可以看成是后来往前跳,所以方向就确定了。
然后可以猜想证明的是,最优情况下,一定是只往前跳一次。也就是来回两个关卡跳。
如果是来回三个关卡跳,需要的总时间有两个,一个是跳跃总时间,一个是干掉该层怪物所需要的时间。
后者时间是固定的,我们来看前者。
三个关卡来回跳的转移次数是6次,而三个关卡来回跳可以看成两个两个关卡的来回跳,同样是转移6次,两者时间相同。(从三个关卡最左边开始)
如果是来回四个关卡跳,则转移次数是9次,而两个两个关卡来回跳外加一次跳,转移次数是7次,后者更优。
所以我们就只用关心来回两个关卡来回跳即可。
设表示干掉前个关卡的怪物所需要的最小时间。
首先可以直接从第个关卡转移过来,然后采用三种方法中最小的一个干掉第个关卡的怪物。
或者从第个关卡转移过来,考虑在第个关卡和第个关卡来回跳,分别考虑第个关卡采用三种方式和第个关卡采用的三种方式,取最小值。
注意的是如果在考虑第个关卡时,如果采用第一种方式,然后跳到第关卡时,不需要再跳回到第个关卡。
还有就是在考虑第个关卡和第个关卡来回跳的时候,不要算上第个关卡跳到第个关卡的转移时间。
神奇的代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } const int N = 1e6 + 8; LL r1, r2, r3; LL a[N]; LL f[N]; LL d, n; LL fuck0(int i){ return r1 * a[i] + r3; } LL fuck1(int i){ return r2 + r1; } LL fuck2(int i){ return r1 * a[i] + r1 + r1; } int main(void) { read(n); read(r1); read(r2); read(r3); read(d); for(int i = 1; i <= n; ++ i) read(a[i]); f[1] = fuck0(1); for(int i = 2; i <= n; ++ i){ f[i] = min({ f[i - 1] + d + fuck0(i), f[i - 1] + d + d + d + min(fuck1(i), fuck2(i)), f[i - 2] + d + d + d + d * (i != n) + min(fuck1(i - 1), fuck2(i - 1)) + fuck0(i), f[i - 2] + (i != 2) * d + d + d + d + min(fuck1(i - 1), fuck2(i - 1)) + min(fuck1(i), fuck2(i)) }); } write(f[n], '\n'); return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/13607003.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现