牛客寒假算法基础训练营day-1

2020-04-30  本文已影响0人  _NewMoon

写在前面:寒假之前报名了牛客的寒假算法训练营,当时没有好好参加,主要还是自己太菜,正好临近五一,所以计划每天学习一下当时比赛时候的题目和相关算法,因为这次训练营的题目是针对竞赛的,所以很多知识点我都还没学过,所以这里只记录一下相对来说简单一点的题目,后续学习了相关知识点后会持续补充~

官方题解地址:https://ac.nowcoder.com/discuss/364600?type=101&order=0&pos=1&page=3&channel=-1

A. honoka和格点三角形

因为是格点三角形且面积为1,所以只存在两种形式的三角形:底为2高为1的和底为1和高为2的,题目还要求三角形至少有一条边是与坐标轴平行的,所以我们再分为两条边都平行和只有一条边平行这两类进行讨论:
贴张我自己的笔记:


note

代码:

#include <iostream>
#include <cstdio>

using namespace std;
typedef long long LL;

const int mod = 1e9+7;
LL n,m;
int main()
{
    LL ans = 0;
    cin>>n>>m;
    
    //两边平行
    ans = 4 * ((n-1)*(m-2)%mod + (n-2)*(m-1)%mod)%mod;
    
    //底边与x轴平行
    ans = (ans + 2 *(n-1)*(m-2)%mod*(m-2) + 2*(m-1)*(n-2)%mod*(n-2)%mod)%mod;
    
    //底边与y轴平行
    ans = (ans + 2 * (m-1)*(n-2)%mod*(m-2)%mod + 2*(n-1)*(m-2)%mod*(n-2)%mod)%mod;
    
    cout<<ans<<endl;
    return 0;
}

G.eli和字符串

对每个字母都预处理一个数组,然后用尺取法(双指针)对26个数组依次进行扫描,更新答案

代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <unordered_map>

using namespace std;

const int N = 200100;
string s;
int n,k;
int a[30][N];

int main()
{
    cin>>n>>k;
    cin>>s;
    s = " " + s;
    
    //预处理
    for(int i = 0; i<26; i++){
        for(int j = 1; j<=n; j++)
            if(s[j] == ('a' + i))
                a[i][j] = 1;
    }
 
    int ans = 1e9;
    for(int i = 0; i<26; i++){
        int res = N,l = 1,r = 1,sum = 0;
        while(1){
            while(r<=n && sum<k) sum += a[i][r++];
            if(sum < k) break;
            res = min(res,r-l);
            sum -= a[i][l++];
        }
        //cout<<res<<endl;
        ans = min(ans,res);
    }
    if(ans == N) cout<<-1<<endl;
    else cout<<ans<<endl;
    
    return 0;
}

H.nozomi和字符串

也是用尺取法,找到满足条件的最大区间

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

string s;
int n,k;

//尺取法
int solve(char a,char b){
    int l = 0, r = 0,cnt = 0,res = 1;
    
    for(int i = 0; i<n; i++){
        if(s[i] == a){
            if(cnt <k){
                cnt++;
                r++;
            }
            else{
                while(l<=r && s[l] != a) l++;
                l++,r++;
            }
        }
        else r++;
        res = max(res,r-l);
    }
    return res;
}
int main()
{
    cin>>n>>k>>s;
    int ans = max(solve('0','1'),solve('1','0'));
    cout<<ans<<endl;
    return 0;
}

I.nico和niconiconi

DP问题,dp[i]表示前i个字符的最大得分,状态转移方程为:
if(s.substr(i - 3, 4) == "nico")then dp[i] = max(dp[i],dp[i - 4] + a)
if(s.substr(i - 5, 6) == "niconi")then dp[i] = max(dp[i],dp[i- 6] + b)
if(s.substr(i - 9,10) == "niconiconi")then dp[i] = max(dp[i], dp[i - 10]+ c)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>

using namespace std;

const int N = 300010;
int a,b,c;
int n;
long long dp[N];
string s;

int main()
{
    cin>>n>>a>>b>>c>>s;
    s = " " + s;
    long long ans = 0;
    if(n>=4){
        for(int i = 1; i<=n; i++){
            dp[i] = dp[i-1];
            if(i>=4)
                if(s.substr(i-3,4) == "nico") 
                    dp[i] = max(dp[i-4] + a,dp[i]);
            if(i>=6){
                if(s.substr(i-5,6) == "niconi")
                    dp[i] = max(dp[i-6] + b,dp[i]);
            }
            if(i>=10){
                if(s.substr(i-9,10) == "niconiconi")
                    dp[i] = max(dp[i-10] + c,dp[i]);
            }
            
        }
        ans = dp[n];
    }
    //for(int i = 1; i<=n; i++) cout<<dp[i]<<endl;
    cout<<ans<<endl;
    return 0;
}

至此,day-1还有一个图论题,一个数论题,后面再更新~
2020 4.30 凌晨0.27分,顶不住了,溜了。

上一篇下一篇

猜你喜欢

热点阅读