pezhzh的快乐寒假作业[2024/1/17]

A - 守望者的逃离

快乐贪心一次过!

#include<bits/stdc++.h>
using namespace std;
int m, s, t, tt, ss;
int main(){
	cin >> m >> s >> t;
	tt = t, ss = s;
	while(t > 0 && s > 0){
		if(m / 10 > 0){
			s -= 60;
			t --;
			m -= 10;
		}else if(s >= 60 && t > 1 + (m < 6) && m > 1){
			s -= 60;
			t -= 2 + (m < 6);
			m = (m + 2) % 4;	
		}else if(s >= 120 && t >= 7){
			s -= 120;
			t -= 7;
		}else{
			s -= 17;
			t --;
		}
	}
	if(s <= 0) cout << "Yes" << endl << tt - t;
	else cout << "No" << endl << ss - s;
}

 可以从减少while次数的角度优化程序;

B - Weather

一眼bfs;

前面是寒假打的,现在是补作业的时候啦;

用dp,别整你的bfs力!

对第i个数我们只需要统计到它时前面需要将多少个非负数改成负数就ok;

在反向如上操作一次统计到这的非正数改正数;

然后算哪个i存的数最小就好啦;

#include<bits/stdc++.h>
using namespace std;
int n, dp[100010], pd[100010], a[100010], res = 100010;
int main(){
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	cin >> n;
	for(int i = 1; i <= n; i ++){
		cin >> a[i];
		dp[i] = dp[i - 1] + (a[i] >= 0);
	}for(int i = n; i > 0; i --)
		pd[i] = pd[i + 1] + (a[i] <= 0);
	for(int i = 1; i < n; i ++){
		res = min(res, pd[i + 1] + dp[i]);
	}cout << res;
}

需要注意的是本题要求用输入文件输入;

所以得将input.txt设为输入流;

C - WOW Factor

我觉得我似乎应该放个题目;

洛谷题号是:CF1178B;

因为vv组成w用的一定是相邻的vv;

所以一串长度为n的相邻的vv最多能产出n-1个w;

对于每个o来说,它能合成的wow是由它前面的不同w数量与后面的不同w数量相乘得来的;

用dp统计每个o前面有多少不同的w;

再反向统计后面有多少w;

把相乘的结果累加就ok啦;

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
char ch;
long long s, cou, out, dp[N], pd, b[N];
int main(){
	ch = getchar();
	while(ch != '\n'){
		if(ch == 'o'){
			if(cou - b[out - 1] - 1 && out != 0) dp[out] = dp[out - 1] + (cou - b[out - 1] - 2);
			else if(!out) dp[out] = (cou > 1 ? cou - 1 : 0);
			else dp[out] = dp[out - 1];
			b[out ++] = cou;
		}cou ++;
		ch = getchar();
	}b[out] = cou;
	for(long long i = out - 1; i >= 0; i --){
		if(b[i + 1] - b[i] - 1) pd = pd + (b[i + 1] - b[i] - 2);
		else pd = pd;
		s += dp[i] * pd;
	}
	cout << s;
}

b数组记录的是每个o的位置;

cou就像for循环里的i一样,还顺手统计出了字符串的长度;

每个连串vv的数量就是两个o之间的间隔;

s是结果;

D - 最大差值

洛谷题号:P5146;

因为必须得是不同的两个数相减;

所以要从第二个开始;

对于每一个数a;

我们都与前面输入的数的最小值取差;

再在之前的最小值与a之中取更小的那个作新的最小值;

输出这个过程中得到的最大的差值;

#include<bits/stdc++.h>
using namespace std;
long long n, a, mi, ma = -1e10;
int main(){
	cin >> n >> mi;
	while(n -- > 1){
		scanf("%lld", &a);
		ma = max(ma, a - mi);
		mi = min(a, mi);
	}cout << ma;
} 

E - Approximating a Constant Range

洛谷题号:R153978524;

这是一道经典的dp题;

但是我非要拿指针做;

真正的O(n)战士永不言弃!

我们使用 fl 和 f 来分别存储最靠近新输入的数字的连续的数字的头;

用 L 来存储这个合法的串的尾;

例如:112221111222

           l         fl     f    i

假设下一个数是3:

1122211112223

l         fl     f      i

那先重置 fl 和 f;

1122211112223

l         fl     f      i

l                fl     f

再将 L 前移到 fl 的位置就合法了;

1122211112223

                 fl     f

                  l     f

如果下一个数是1:

1122211112221

l         fl     f      i

同样是重置 fl 和 f;

1122211112221

l         fl     f      i

l                fl     f

但是不需要将 L 前移;

那再来一个0呢?

11222111122210

l                fl     f i

重置 fl 和 f;

11222111122210

l                fl     f i

l                       fl f

将 L 前移到 fl 的位置;

11222111122210

l                       fl f

                        l f

得到合法的“10”;

程序实现如下:

#include<bits/stdc++.h>
using namespace std;
int n, l, sm, bi, f, fl, a[100010], res;
int main(){
	cin >> n;
	for(int i = 0; i < n; i ++){
		cin >> a[i];
		if(i != 0){
			if(bi == sm && a[i] != bi){
				bi = a[i];
				fl = f;
				f = i;
				if(bi < sm) swap(bi, sm);
			}else if(a[i] > bi){
				fl = f;
				f = i;
				l = fl;
				sm = bi;
				bi = a[i];
			}else if(a[i] < sm){
				fl = f;
				f = i;
				l = fl;
				bi = sm;
				sm = a[i];
			}else if(a[i] != a[i - 1]){
				fl = f;
				f = i;
			}
		}else{
			bi = a[i];
			sm = a[i];
		}
		res = max(res, i - l + 1);
	}cout << res;
}

有点绕的说实话;

不建议使用;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值