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;
}
有点绕的说实话;
不建议使用;