郑轻19级新生周赛(5)-殷杰飞专场题解

稍后补上代码毕竟有的题还有锅比如J数据就很水(手动狗头)

A:暴力

2 n 2^n n n 比较小只有 20 20 ,位运算和循环都可以。

B:尺取法,不会的可以百度一下学习。

用一个数组记录当前遍历字符串中每个字符出现的次数,设置一个起始点和结束点,如果当前起始点和结束点包含的字符串
不满足条件,结束点往后遍历一个字符,数组中相应的字符个数+1,然后判断是否满足条件,如果满足条件,更新答案,
然后起始点向后移动一个字符,移动前将对应的字符在数组中的个数-1,重复上述步骤。

C:规律/暴力

先排序,然后用公式推一下,每一个位置的元素和整个数组组成 n n 个对子,那么第一维的值就是 k n \frac{k}{n} ,第二维是 k k % n n ,
最后特判一下 n n k k 余数的情况。

D: 暴力

等差数列,通项桶排标记, f o r for 遍历即可。

E:规律

拿红球黑球放黑球:相当于拿走一个红球
拿红球红球放红球:相当于拿走一个红球
拿黑球黑球放红球:相当于两个黑球换一个红球

不难发现,只要黑球个数是偶数,最后就一定是红球。随机拿出的两个球的颜色不会对最终答案产生影响。

F:暴力枚举

暴力枚举长度,然后遍历序列。

G:求中位数

H:模拟

特判下闰年的情况。(这里涉及到一个好用的公式蔡勒公式/基姆拉尔森计算公式,自行百度)

参考代码:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
using namespace std;
#define ll long long
 
int weekday(int Y,int M,int D) {//返回0 1 2 3 4 5 6分别表示周日 周一...周六
    int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    Y -= M < 3;
    return (Y + Y/4 - Y/100 + Y/400 + t[M-1] + D) % 7;
}
int main() {
    int y,m,d;
    while(~scanf("%d%d%d",&y,&m,&d)) {
        int x=weekday(y,m,d);
        for(int i=y+1;;i++){
            if(!((i%4 == 0 && i%100 != 0) || i %400 == 0)){
                if(m==2&&d==29){
                    continue;
                }
            }
            if(weekday(i,m,d)==x){
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}

J:贪心/动态规划

考虑贪心 :负数乘以最小值、正数乘以最大值
三个数组,第一个存从前到当前位置 p a i p*a_i 的最优值,一个数组存从后到当前位置为止 r r * a i a_i 的最大值,遍历一边序列用 q a i q * a_i 加上提前算好的两个数组在当前位置的值,遍历的时候记录最优值。超级强的同学 可以考虑用动态规划写, d p [ i ] [ j ] dp[i][j] 表示前 i i 个数中已经取了 j j 个数的最大值。(相当于 p p r r q q 放在一个长度为 3 3 的数组里面)

参考代码:

有兴趣的,动态规划(线性递推)自行学习

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
using namespace std;
#define ll long long
const ll  inf = 3e18;
ll ans[100005],dp[3][100005];
int main() {
    ll n,a,b,c;
    while(~scanf("%lld%lld%lld%lld",&n,&a,&b,&c)) {
        for(int i=1; i<=n; i++) {
            scanf("%lld",&ans[i]);
        }
        dp[0][0]=-inf;
        dp[1][0]=-inf;
        dp[2][0]=-inf;
        for(ll i=1; i<=n; i++) {
            dp[0][i]=max(dp[0][i-1],a*ans[i]);
            dp[1][i]=max(dp[1][i-1],dp[0][i]+b*ans[i]);;//保证1 ≤ i ≤ j 
            dp[2][i]=max(dp[2][i-1],dp[1][i]+c*ans[i]);//保证1 ≤ i ≤ j ≤ k ≤ n
        }
        printf("%lld\n",dp[2][n]);
    }
    return 0;
}

当然既然都说了是线性递推啦,那么就可以这样写:

#include<bits/stdc++.h>
using namespace std;
const long long inf = 3e18;
int main() {
	long long n,m,p,q,r;
	while(~scanf("%lld%lld%lld%lld",&n,&p,&q,&r)) {
		long long a=-inf,b=-inf,c=-inf;
		for(int i=0; i<n; i++) {
			scanf("%lld",&m);
			a=max(a,m*p);
			b=max(b,a+m*q);
			c=max(c,b+m*r);
		}
		printf("%lld\n",c);
	}
	return 0;
}
发布了293 篇原创文章 · 获赞 212 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/nuoyanli/article/details/103111351
今日推荐