牛客周赛 Round 3【题解完成】

113 阅读4分钟
题目难度知识点
A 游游的7的倍数签到/暴力枚举
B 游游的字母串枚举
C 游游的水果大礼包枚举
D 游游的矩阵权值★★数学+推式子

image.png

image.png 总的来说还是不错的,AB一发过,C题先想到了dfs搞一下,后面又想到了DP搞一下,都是会超时的,这个是意料之中的就是想先搞一个暴力再优化,后面发现只需枚举一种包装的个数,另一种基于剩余的计算出来时间为O(n),D关键点在于如何构造,可以发现是数学题故应该是推式子o(1)搞出来,先没取模交一发,然后取模+化简中间漏了一点后面开始修,最后又wa一发是取模中间过程有一点爆LL了,然后又依次的仔细取模过了。果然每次遇到取模题,尤其公式长的时候每次总会中间LL爆,确实该注意。

游游的7的倍数

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],n;
int main(void)
{
    string s; cin>>s;
    for(int i=0;i<=s.size();i++)//枚举插入的位置
    {
        string temp;
        temp=s.substr(0,i);
        for(int j=0;j<=9;j++) //枚举插入的数
        {
            string temp1=temp;
            temp1+=to_string(j);
            temp1+=s.substr(i,s.size()-i);
            LL flag=stol(temp1);
            if(flag%7==0&&flag)
            {
                cout<<temp1;
                return 0;
            }
        }
    }
    return 0;
}

游游的字母串

最终情况可以确定,计算每种情况的结果取一个min。由于是环故每一个字母到另一个字母的路径有两条取一个min。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL cnt[N][35];
int main(void)
{
    string s; cin>>s;
    for(int i=0;i<s.size();i++)
    {
        int temp=s[i]-'a';
        for(int j=0;j<=25;j++)
        {
            cnt[i][j]=abs(temp-j);
            cnt[i][j]=min(abs(temp-j),26-abs(temp-j));
        }
    }
    LL ans=1e18;
    for(int i=0;i<=25;i++)
    {
        LL temp=0;
        for(int j=0;j<s.size();j++) temp+=cnt[j][i];
        ans=min(ans,temp);
    }
    cout<<ans;
    return 0;
}

游游的水果大礼包

暴力做法:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
void dfs(int cnt1,int cnt2,int suma,int sumb,LL sum)
{
    ans=max(ans,sum);
    if(suma==0 || sumb==0) return;
    if(suma>=2&&sumb>=1) dfs(cnt1+1,cnt2,suma-2,sumb-1,sum+a);
    if(suma>=1&&sumb>=2) dfs(cnt1,cnt2+1,suma-1,sumb-2,sum+b);
}
int main(void)
{
    cin>>n>>m>>a>>b;
    dfs(0,0,n,m,0);
    cout<<ans;
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
int main(void)
{
    cin>>n>>m>>a>>b;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j-1];
            if(i-2>=0&&j-1>=0) f[i][j]=max(f[i][j],f[i-2][j-1]+a);
            if(i-1>=0&&j-2>=0) f[i][j]=max(f[i][j],f[i-1][j-2]+b);
        }
    }
    cout<<f[n][m];
    return 0;
}

正解:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
typedef long long int LL;
LL n,m,a,b,f[N][N],ans;
int main(void)
{
    cin>>n>>m>>a>>b;
    for(int i=0;i<=1e6;i++)
    {
       LL sum1=2*i;
       LL sum2=i;
       if(sum1>n || sum2>m) break;
       ans=max(ans,i*a+min(n-sum1,(m-sum2)/2)*b);
    }
    cout<<ans;
    return 0;
}

游游的矩阵权值

可以发现,中间的贡献是4次,边上是3次,角上是2次。 故中间一块用最大的,边上的用次大的,角上用最小的。可以用最小的和最大的退出次大的。

//这个是没考虑mod的式子
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
int main(void)
{
    cin>>n;
    LL cnt4=(n-2)*(n-2);//3的总个数
    LL sum=(n*n)*(n*n+1)/2;//总的数量
    LL temp=n*n-cnt4;//剩余的2-3的个数
    LL sum1=sum-(temp)*(temp+1)/2;
    LL ans=0;
    ans+=sum1*4;
    ans+=10*2;
    ans+=(sum-sum1-10)*3;
    cout<<ans;
    return 0;
}

化简后取模的正解:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
LL qsm(LL a,LL b,LL p)
{
    LL sum=1;
    while(b)
    {
        if(b&1) sum=sum*a%p;
        a=a*a%p;
        b>>=1;
    }
    return sum%p;
}
int main(void)
{
    cin>>n;
    n=n%mod;
    LL temp1=(n*n)%mod;
    LL sum1=2*temp1*(temp1+1)%mod;
    LL sum2=(2*n-2)*(4*n-3)%mod;
    cout<<(sum1-sum2-10+mod)%mod;
    return 0;
}

关于有时候用long long 但是mod的不够还是爆long long的小trick,可以用__int128计算最后再强制的转long long 输出就行了,这样可以极大的避免有时候mod的不足中间爆long long的情况。

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long int LL;
LL n;
LL qsm(LL a,LL b,LL p)
{
    LL sum=1;
    while(b)
    {
        if(b&1) sum=sum*a%p;
        a=a*a%p;
        b>>=1;
    }
    return sum%p;
}
int main(void)
{
    cin>>n;
    __int128 temp1=(n*n)%mod;
    __int128 sum1=2*temp1*(temp1+1)%mod;
    __int128 sum2=(2*n-2)*(4*n-3)%mod;
    cout<<(LL)(sum1-sum2-10+mod)%mod;
    return 0;
}