【题解】2020牛客寒假算法基础集训营1

比赛链接:https://ac.nowcoder.com/acm/contest/3002
其他比赛题解:
【题解】2020牛客寒假算法基础集训营2
【题解】2020牛客寒假算法基础集训营3
【题解】2020牛客寒假算法基础集训营4
【题解】2020牛客寒假算法基础集训营5




A - honoka和格点三角形(计算几何)

原题链接:https://ac.nowcoder.com/acm/contest/3002/A

  • 思路: 因为三角形面积为 1 且至少有一条边平行于 x 轴或者 y 轴,那么这条边的长度为 1 或者 2,所以枚举边长为 1 的平行于 x 轴和 y 轴的情况,加上边长为 2 的平行于 x 轴和 y 轴的情况,再减掉重复的,也就是同时存在边长为 1 和 2 都平行于坐标轴的情况。要注意的就是减掉后答案可能为负数,所以要加上 mod 防止出现负数。

Code:

#include <iostream>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int main(){
    ll n,m;    cin>>n>>m;
    ll ans1=((n-2)*2%mod)*((m-1)*m%mod)%mod;
    ll ans2=((n-1)*2%mod)*((m-2)*m%mod)%mod;
    ll ans3=((m-2)*2%mod)*((n-1)*n%mod)%mod;
    ll ans4=((m-1)*2%mod)*((n-2)*n%mod)%mod;
    ll ans5=((n-2)*2%mod)*((m-1)*2%mod)%mod;
    ll ans6=((n-1)*2%mod)*((m-2)*2%mod)%mod;
    ll ans=((ans1+ans2)%mod+(ans3+ans4)%mod-(ans5+ans6)%mod+mod)%mod;
    cout<<ans<<endl;
    return 0;
}


B - kotori和bangdream(签到)

原题链接:https://ac.nowcoder.com/acm/contest/3002/B

  • 思路: 数学期望期望等于总数乘以概率乘以分值。

Code:

#include <iostream>
#include <iomanip>
using namespace std;
int main(){
    int n,x,a,b;    cin>>n>>x>>a>>b;
    double ans = n*(x*0.01)*a+n*((100-x)*0.01)*b;
    cout<<fixed<<setprecision(2)<<ans<<endl;
    return 0;
}


D - hanayo和米饭(签到)

原题链接:https://ac.nowcoder.com/acm/contest/3002/D

  • 思路: 当时的想法是排个序,然后如果存在断续的,断续的那个数就是答案,如果不存在,就判断开头或者结尾的数是否存在,不存在的那个数就是答案。但其实有更简单的方法,就是先通过公式 (1+n)*n/2 求出 1 到 n 的总和,再减掉现有的数的总和就是答案。

Code:

#include <iostream>
#include <algorithm>
using namespace std;
int a[100010];
int main(){
    int n;    cin>>n;
    for(int i=1;i<=n-1;i++)
        cin>>a[i];
    sort(a+1,a+n);
    int vis=0;
    for(int i=1;i<n-1;i++){
        if(a[i]+1!=a[i+1]){
            vis=1;
            cout<<a[i]+1<<endl;
        }
    }
    if(!vis){
        if(a[1]!=1)    cout<<1<<endl;
        else if(a[n]!=n)    cout<<n<<endl;
    }
    return 0;
}


E - rin和快速迭代(数论)

原题链接:https://ac.nowcoder.com/acm/contest/3002/E

  • 思路: 就是一道简单的求因子数的题目。可以分为两种,一种就是该数是完全平方数,那么最中间的因子数只有一个(其实就是两个相同的),一种就是不为完全平方数,那么因子数就是对称的。要注意的就是,判断一个数是否为完全平方数不能用 sqrt(n) * sqrt(n)==n来判断,要不然就得强制转换为 int 类型,即用 (int)sqrt(n) * (int)sqrt(n)==n 来判断。

Code:

#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
ll ans;
ll f(ll x){
    ll sum=0,cnt=0;
    for(int i=1;i*i<=x;++i){
        if(x%i==0){
            if(i*i==x)    sum++;
            else    cnt++;
        }
    }
    sum+=cnt*2;
    return sum;
}
int main(){
    ios::sync_with_stdio(0);
    ll n;    cin>>n;
    while(n!=2){
        ans++;
        n=f(n);
    }
    cout<<ans<<endl;
    return 0;
}


G - eli和字符串(字符串)

原题链接:https://ac.nowcoder.com/acm/contest/3002/G

  • 思路: 由于字符串只由 26 种小写字母组成,那么可以先统计这 26 种字母分别的数量,同时统计每一种字母每一个的位置,如果存在相同字母数量大于等于 k 的就标记,同时记录此时子串的最小的长度,不断地更新。如果没有一种字母的数量大于等于 k 的就直接输出 -1 即可。具体见代码。

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int a[30],b[30][200010];
int main(){
    int ans=300000;
    int n,k;    cin>>n>>k;
    string str;    cin>>str;
    int vis=0;
    for(int i=0;i<str.length();i++){
        a[str[i]-'a'+1]++;
        b[str[i]-'a'+1][a[str[i]-'a'+1]]=i;
        if(a[str[i]-'a'+1]>=k){
            vis=1;
            ans=min(ans,b[str[i]-'a'+1][a[str[i]-'a'+1]]-b[str[i]-'a'+1][a[str[i]-'a'+1]-k+1]+1);
        }
    }
    if(!vis){
        cout<<-1<<endl;
        return 0;
    }
    if(k==1)    cout<<1<<endl;
    else
        cout<<ans<<endl;
    return 0;
}


H - nozomi和字符串(二分+字符串)

原题链接:https://ac.nowcoder.com/acm/contest/3002/H

  • 思路: 因为要求长度最大值,所以可以二分查找。统计 0 和 1 的前缀和,然后对于每个查找的长度,如果相应长度的 0 和 1 的数量和的最小值小于等于 k ,说明符合,继续不断查找,直到不符合即为最长。当然,如果 k 大于等于 n/2,那么长度一定是 n。

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,k;
const int N=2e5+100;
int sum[N][2];
bool check(int x){
    for(int i=1;i<=n-x;i++){
        if(min(sum[i+x-1][0]-sum[i-1][0],sum[i+x-1][1]-sum[i-1][1])<=k)
            return true;
    }
    return false;
}
int main(){
    cin>>n>>k;
    string str;    cin>>str;
    if(k>=n/2){
        cout<<n<<endl;
        return 0;
    }
    sum[1][str[0]-'0']=1;
    for(int i=1;i<n;i++){
        sum[i+1][0]=sum[i][0];
        sum[i+1][1]=sum[i][1];
        sum[i+1][str[i]-'0']++;
    }
    int l=1,r=n,ans;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}


I - nozomi和字符串(dp+字符串)

原题链接:https://ac.nowcoder.com/acm/contest/3002/I

  • 思路: 其实是一道简单 dp 的字符串题目。

Code:

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=3e5+10;
ll dp[N];
int main()
{
    int n,a,b,c;    cin>>n>>a>>b>>c;
    string str;    cin>>str;
    ll ans=0;
    for(int i=0;i<n;i++){
        dp[i]=dp[i-1];
        if(i-3>=0 && str.substr(i-3,4)=="nico")
            dp[i]=max(dp[i],dp[i-4]+a);
        if(i-5>=0 && str.substr(i-5,6)=="niconi")
            dp[i]=max(dp[i],dp[i-6]+b);
        if(i-9>=0 && str.substr(i-9,10)=="niconiconi")
            dp[i]=max(dp[i],dp[i-10]+c);
    }
    cout<<dp[n-1]<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值