鑫汇工作室邀请赛2-DIV2题解

· · 个人记录

以下为本次比赛的题解,请没能AC部分题目的同学仔细阅读。

希望发现问题或表述不清楚、不完整的地方的同学通过洛谷私信告诉我,会有相应的酷町豆奖励。

部分无需特别注意的点没有提到,敬请谅解。

本次比赛的题目难度较大(当然对于一些大佬们肯定非常简单),只有一位同学AK,买分这一题只有一位同学AC(除我以外)。

神秘对战游戏比买分那一题难度还要大很多,测试点给我的脑子都配炸了。

U190399 鑫汇工作室邀请赛2-DIV2签到题

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    cout<<1;
}

U190651 斐波那契数列

根据题意,输出斐波那契数列的第n个数。

斐波那契数列的前2个数都是1,后面的每一个数都是前两个数的和。

n≤90,所以要用long long,不必用高精度进行求解。

F1:递推

学递推的第一课必学内容。

代码:

#include <bits/stdc++.h>
using namespace std;
long long f[91];
int n;
int main()
{
    cin>>n;
    f[1]=f[2]=1;
    for(int i=3;i<=n;i++)
    {
        f[i]=f[i-1]+f[i-2];
    }
    cout<<f[n];
}

F2:递归

学递归的第一课必学内容。

代码:

#include <bits/stdc++.h>
using namespace std;
long long f(int n)
{
    if(n==1) return 1;
    if(n==2) return 1;
    return f(n-2)+f(n-1);
}
int main()
{
    int a;
    cin>>a;
    cout<<f(a);
}

显然,这样写必定会超时。

原因:分支过多,大量相同的东西被反复算。

献上一张丑陋的图片:

可以看到f(3),f(2),f(1)都被重复算了。

当n的数值逐渐增多,被重复算的函数的数量和次数也增多。

记忆化搜索可以有效地避免这种情况。

我们可以将算过的函数值存在一个数组中,当发现还要再算时,直接把这个数组中的那个函数的数值带进去。

具体可以询问老师或百度一下。

改进后的代码:

#include <bits/stdc++.h>
using namespace std;
long long f1[91];
long long f(int n)
{
    if(f1[n]!=-1) return f1[n];
    if(n==1) return 1;
    if(n==2) return 1;
    return f1[n]=f(n-2)+f(n-1);
}
int main()
{
    memset(f1,-1,sizeof(f1));
    int a;
    cin>>a;
    cout<<f(a);
}

U190705 买分

根据题意,如果可以买来n分,输出需要花的最少的钱;如果不可以,输出-1。

先设定:

an表示买n分需要an元(1≤n≤10,n为整数,an是在买分表里面的)

fn表示买n分最少需要fn元(n为正整数)

这道题目需要分段递推:

第一段:n≤10

第二段:n>10

我们先看第一段:

因为不一定买的分越多价钱越高,所以需要依次比较。

在看第二段:

取每种买法的最小值。

由于我的表达能力十分欠缺,举个例子说明一下:

假设我要买2分,

第一种:a1+a1

第二种:a2

取最小值即可。

假设我要买3分,

第一种:a1+a1+a1

第二种:a1+a2

第三种:a3

取最小值即可。

假设我要买11分,

第一种:f1+a10

第二种:f2+a9

第三种:f3+a8

第四种:f4+a7

第五种:f5+a6

第六种:f6+a5

第七种:f7+a4

第八种:f8+a3

第九种:f9+a2

第十种:f10+a1

取最小值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int n,a[15],f[100005],x;//a,f的意思和前文相同 
int main()
{
    for(int i=1;i<=10;i++) cin>>a[i];
    cin>>n>>x;
    for(int i=1;i<=10;i++)
    {
        f[i]=a[i];
        for(int j=1;j<i;j++)
        {
            f[i]=min(f[i],f[i-j]+a[j]);//取最小值 
        }
    }//第一段 
    for(int i=11;i<=n;i++)
    {
        f[i]=0x3f3f3f3f;
        for(int j=1;j<=10;j++)
        {
            f[i]=min(f[i],f[i-j]+a[j]);//取最小值 
        }
    }//第二段 
    if(f[n]<=x) cout<<f[n];
    else cout<<-1;
}

U192775 加法和乘法

根据题意,输出两个数的和与积。

由于这两个数很大,需要用到高精度。

高精度加法和乘法可以看一下代码和注释、询问老师、百度一下。

#include <bits/stdc++.h>
using namespace std;
string s1,s2;
void cf(string s1,string s2)
{
    int a[105],b[105],c[10050];
    memset(a,0,sizeof(a));//计算前一定要清0,在函数内定义的数组里的数字是随机的 
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    a[0]=s1.size(),b[0]=s2.size();//数组的第0位存储这个大数的位数 
    for(int i=1;i<=a[0];i++)
    {
        a[i]=s1[a[0]-i]-48;//倒序存储各位数值 
    }
    for(int i=1;i<=b[0];i++)
    {
        b[i]=s2[b[0]-i]-48;//倒序存储各位数值 
    }
    //高精度乘法 
    c[0]=a[0]+b[0];//假设结果的位数 
    for(int i=1;i<=a[0];i++)//不计算进位时每位的结果 
    {
        for(int j=1;j<=b[0];j++)
        {
            c[i+j-1]+=a[i]*b[j];
        }
    }
    int jw=0;//用来存储进位 
    for(int i=1;i<=c[0];i++)//计算进位 
    {
        c[i]+=jw;//加上进位 
        jw=c[i]/10;//进位是现在这一位除以10 
        c[i]%=10;//现在的这一位%10 
    }
    if(c[c[0]]==0) c[0]--;//调整结果的位数 
    for(int i=c[0];i>=1;i--) cout<<c[i];
}
void jf(string s1,string s2)
{
    int a[105],b[105],c[10050];
    memset(a,0,sizeof(a));//计算前一定要清0 
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    a[0]=s1.size(),b[0]=s2.size();//数组的第0位存储这个大数的位数 
    for(int i=1;i<=a[0];i++)
    {
        a[i]=s1[a[0]-i]-48;//倒序存储各位数值 
    }
    for(int i=1;i<=b[0];i++)
    {
        b[i]=s2[b[0]-i]-48;//倒序存储各位数值 
    }
    //高精度加法 
    c[0]=max(a[0],b[0]);//暂且不考虑最高位进位的情况
    int jw=0;//用来存储进位 
    for(int i=1;i<=c[0];i++)//先判断到c[0]位 
    {
        c[i]=a[i]+b[i]+jw;//加上两数相同的位数和进位 
        jw=c[i]/10;//进位等于c[i]除以10 
        c[i]%=10;//某一位不可能是个多位数 
    }
    if(jw)//如果最高位有进位 
    {
        c[0]++;//位数加1 
        c[c[0]]=jw;//最高位等于这个进位 
    }
    for(int i=c[0];i>=1;i--) cout<<c[i];
}
int main()
{
    cin>>s1>>s2;
    jf(s1,s2);
    cout<<" ";
    cf(s1,s2);
}

U190401 鑫汇工作室邀请赛2-DIV2结束题

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    cout<<1;
}