2020-09-03 13:16阅读: 321评论: 1推荐: 1

Codeforces Round #666 (Div. 1)

A. Multiples of Length (CF 1396 A)

题目大意

给定一个n个数字的数组a,你需要进行三次操作。

每次操作,选择一个区间,然后对区间里的每一个数,加上一个该区间长度的倍数。不同数加的数可以不同。

输出三次操作的区间以及该区间每个数所加的数。

可以证明保证有解。

解题思路

构造题。为应对任意数字的情况,我们让每个ai的系数变为0

如果n=1,那么答案就是

1  1

a1

1  1

0

1  1

0

否则就

1  1

a1

1  n

0  n×a2  n×a3    n×an

2  n

(n1)×a2  (n1)×a3    (n1)×an

神奇的代码
#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)

题目大意

初始n堆石子,THL轮流拿,T先。一个人不能拿上一轮对方拿的那堆石子。当两者均采取最优策略的情况下,谁必赢。

解题思路

博弈题。

很显然,n=1T赢。

n=2时,若两堆石子数相同,则HL赢,否则T赢。

其余的,他们采取最优策略,即总是拿石子数最多的那堆,模拟即可得到答案。

或者可以这样考虑,因为最后是剩下两堆石子的,而如果两堆石头数量相同,则HL赢。那么,我们假设最后剩下的是第i堆和第j堆,初始ai<ajHL为了赢,需要花ajai轮,使得这两堆相同,剩下的取其他堆,只要此时剩下的其他堆的数量是偶数,那么最后的局面就进入HL必赢局面。

也即k=1nakaiaj(ajai)=k=1nak2aj是偶数,那么HL必赢。

由于2aj时偶数,不改变结果的奇偶性,所以判断k=1nak的奇偶性即可。

特别的,如果最大堆的数量大于其他堆数量的和,则T必赢。

综上,如果最大堆的数量大于其他堆数量的和或k=1nak是奇数,则T必赢,否则HL必赢。

神奇的代码
#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)

题目大意

n个关卡,初始第一个关卡,第i个关卡有ai1HP的普通怪物和12HPBoss怪物。

你有三种枪:

  • 手枪,对一只怪物造成1HP伤害,花费r1时间
  • 激光枪,对所有怪物造成1HP伤害,花费r2时间
  • AWP,直接干掉一只怪物,花费r3时间

除了第二种,其余枪要在干掉该关卡的普通小怪后才能对Boss造成伤害。且如果对Boss造成伤害,且Boss未死时,必须转移到上一个或下一个关卡。当然,干掉完当前关卡的怪物需要手动转移到下一个关卡。

转移关卡花费d时间。

问干掉Boss需要的最短时间。

数据保证r1r2r3

解题思路

干掉一个关卡的所有怪物,我们有三种方法。

  • 手枪+AWP
  • 激光枪+手枪
  • 手枪+手枪

第一种很简单,干完该关卡boss后就跳到下一个关卡。

关键就是第二个和第三个,它会跳到其他关卡,然后再跳回来。问题就是会往哪跳,跳多远。

首先任何往后跳的都可以看成是后来往前跳,所以方向就确定了。

然后可以猜想证明的是,最优情况下,一定是只往前跳一次。也就是来回两个关卡跳。

如果是来回三个关卡跳,需要的总时间有两个,一个是跳跃总时间,一个是干掉该层怪物所需要的时间。

后者时间是固定的,我们来看前者。

三个关卡来回跳的转移次数是6次,而三个关卡来回跳可以看成两个两个关卡的来回跳,同样是转移6次,两者时间相同。(从三个关卡最左边开始)

如果是来回四个关卡跳,则转移次数是9次,而两个两个关卡来回跳外加一次跳,转移次数是7次,后者更优。

所以我们就只用关心来回两个关卡来回跳即可。

f[i]表示干掉前i个关卡的怪物所需要的最小时间。

首先可以直接从第i1个关卡转移过来,然后采用三种方法中最小的一个干掉第i个关卡的怪物。

或者从第i2个关卡转移过来,考虑在第i个关卡和第i1个关卡来回跳,分别考虑第i个关卡采用三种方式和第i1个关卡采用的三种方式,取最小值。

注意的是如果在考虑第n个关卡时,如果采用第一种方式,然后跳到第n1关卡时,不需要再跳回到第i个关卡。

还有就是在考虑第1个关卡和第2个关卡来回跳的时候,不要算上0个关卡跳到第1个关卡的转移时间。

神奇的代码
#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 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(321)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.