Codeforces Round #822 (Div. 2) (A to D)

A. Select Three Sticks

题目链接:Select Three Sticks

###### 题意:

给定 n n n根小木棍,长度均为正整数.你可以进行的操作是:任选一根小木棍,使其长度增加或减少 1 1 1,但保证木棍长度始终为正整数.问至少进行多少次操作,才能找到三根小木棍,使它们构成一个等边三角形.

###### 思路:

一个浅显的策略:若 a ≤ b ≤ c a\leq b\leq c abc,则最小代价为 ∣ c − a ∣ |c-a| ca,因此枚举每相邻三根木棍找最小代价即可.

######

#### B. Bright, Nice, Brilliant

题目链接:Bright, Nice, Brilliant

###### 题意

有一个 n n n层金字塔,第 i i i层有 i i i个房间,从每一层我们可以按如图箭头方向向左下或右下行走,并且我们可以在任意一个房间内放置火把。放置完火把后,从此房间开始(包括此房间)能到达的所有房间明亮值增加 1 1 1.

现规定一个 n i c e nice nice的金字塔定义如下:对于每一层,该层内的每个房间的明亮值相同.并且一个 n i c e nice nice的金字塔 n i c e nice nice值定义为每一层第一个房间明亮值之和.

现给定一正整数 n n n,要求构造一 n n n n i c e nice nice金字塔,使得明亮值最大.

###### 思路

神奇的 z j y zjy zjy一语道破.对于每一层两边,能到达它们的路径是唯一的,因此最大值也是固定的,在两端铺满灯即可,并且发现这样摆放刚好符合 n i c e nice nice要求.摆放示例如下:

1

11

101

1001

10001

###### code

ll T;
ll n;
 
bool book[520][520], tag[520][520];
 
int main() {
	read(T);
	while (T--) {
		read(n);
		for (R ll i=1; i<=n; i++) {
			for(R ll j=1; j<=i; j++) {
				if (j==1 || j==i) writesp(1);
				else writesp(0);
			} putchar('\n');
		}
	}
}
 

#### C. Removing Smallest Multiples

题目链接:Removing Smallest Multiples

###### 题意

有一长度为 n n n的初始集合 S = 1 , 2 , 3 , . . . , n S={1, 2, 3,...,n} S=1,2,3,...,n,以及一目标集合 T ⊂ S T\subset S TS.我们可以对一集合进行操作描述如下:

选定一数值 k ∈ [ 1 , n ] k\in[1,n] k[1,n], 并将集合中 k k k的最小倍数删去,代价为 k k k

求进行若干次操作将集合 S S S变成 T T T的最小代价.

###### 思路:

贪心.一个显然的道理是,只有一个数 n u m num num的约数 c c c被删去了,那么原先可以删去 c c c k k k值,才有可能删除 n u m num num,这样可以使得删除的代价尽量小.

因此比较合适的方法是,一层循环从 1 1 1 n n n枚举 k k k,二层循环枚举 k k k的倍数,能删即删,遇见无需删除则 b r e a k break break,因为后面的数也不可能通过 k k k来删除.

贪心复杂度 O ( n n ) \Omicron(n\sqrt n) O(nn )

###### code

const ll N=1e6+5;
 
ll T;
ll n;
char c[N];
bool book[N];
bool tag[N];
ll res;
 
int main() {
	read(T);
	while (T--) {
		read(n);
		scanf("%s", c+1);
		res=0;
		for (R ll i=1; i<=n; i++) {
			book[i]=c[i]-'0';
			tag[i]=false;
		}
		for (R ll i=1; i<=n; i++) {
			for (R ll j=i; j<=n; j+=i) {
				if (book[j]) break;
				if (tag[j]) continue;
				res+=i; tag[j]=true;
			}
		}
		writeln(res);
	}
}
 

#### D. Slime

题目链接:Slime Escape

###### 题意

在一长度为 n n n的串串上串有 n n n s m i l e smile smile,每个下标串一个,并且每个 s m i l e smile smile上标有一整数数值(可能为负).你作为第 k k k s m i l e smile smile(数值非负),每次可以向左或右移动一步,每碰到一个 s m i l e smile smile,便将其吸收,你的数值变成两 s m i l e smile smile数值之和,被吸收的 s m i l e smile smile消失.

但当你的数值变为负数时,你便会死去.

当你到达 0 0 0 n + 1 n+1 n+1位置时,你便能逃出升天.

试问你能否活着逃出去.

###### 思路

双指针扫描。我们从起始点 k k k开始,开一指针 l l l k − 1 k-1 k1向左扫描, r r r k + 1 k+1 k+1向右扫描,直到扫描路径数值之和为正数时(如果是负数,移动也没啥意义是吧)或到达终点时终止。然后能够移动的限定条件是当前数值必须能够承担指针移动过程中 s u m sum sum值的最小负值,最终进行若干轮扫描即可.复杂度 O ( n ) \Omicron(n) O(n)

###### code

const ll N=2e5+5;
 
ll T;
ll n, now;
ll num[N];
ll ls[N], rs[N], lmx[N], rmx[N];
 
int main() {
	read(T);
	while (T--) {
		read(n); read(now);
		for (R ll i=1; i<=n; i++) read(num[i]);
		ls[0]=rs[n+1]=0; lmx[0]=rmx[n+1]=-0x7fffffff;
		for (R ll i=1; i<=n; i++) ls[i]=ls[i-1]+num[i], lmx[i]=max(lmx[i-1], ls[i]);
		for (R ll i=n; i; i--) rs[i]=rs[i+1]+num[i], rmx[i]=max(rmx[i+1], rs[i]);
		ll l=now-1, r=now+1, ml=0x7fffffff, mr=0x7fffffff, suml=0, sumr=0, nowsum=num[now];
		while (1) {
			while (suml<=0 && l) {
				suml+=num[l]; chkmin(ml, suml);
				--l;
			}
			while (sumr<=0 && r<=n) {
				sumr+=num[r]; chkmin(mr, sumr);
				++r;
			}
			if ((l==0 && nowsum+ml>=0) || (r==n+1 && nowsum+mr>=0)) {
				puts("YES");
				break;
			}
			if (nowsum+ml>=0) {
				nowsum+=suml;
				ml=0x7fffffff; suml=0;
			}
			if (nowsum+mr>=0) {
				nowsum+=sumr;
				mr=0x7fffffff; sumr=0;
			}
			if (nowsum+ml<0 && nowsum+mr<0) {
				puts("NO");
				break;
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值