MJUPC-021_编程挑战系列赛第二十一场(Coding the Future)题解(C++代码)

题目一:二元一次方程组求解

此题原本准备作为新生赛题目的,因此比较简单(题目二、三也是)

{ a 1 x + b 1 y = c 1 a 2 x + b 2 y = c 2 \left\{ \begin{matrix} a_1x+b_1y=c_1\\ a_2x+b_2y=c_2 \end{matrix} \right. {a1x+b1y=c1a2x+b2y=c2
学过线性代数的同学直接可以得出
x = [ c 1 b 1 c 2 b 2 ] [ a 1 b 1 a 2 b 2 ] , y = [ a 1 c 1 a 2 c 2 ] [ a 1 b 1 a 2 b 2 ] x= \frac{ \left[ \begin{matrix} c_1 & b_1 \\ c_2 & b_2 \end{matrix} \right]} {\left[ \begin{matrix} a_1 & b_1 \\ a_2 & b_2 \end{matrix} \right]} ,y= \frac{ \left[ \begin{matrix} a_1 & c_1 \\ a_2 & c_2 \end{matrix} \right]} {\left[ \begin{matrix} a_1 & b_1 \\ a_2 & b_2 \end{matrix} \right]} x=[a1a2b1b2][c1c2b1b2],y=[a1a2b1b2][a1a2c1c2]
没有学过的小可爱也可以通过消元法计算得出
x = c 1 b 2 − c 2 b 1 a 1 b 2 − b 1 a 2 , y = a 1 c 2 − a 2 c 1 a 1 b 2 − b 1 a 2 x=\frac{c_1b_2-c_2b_1}{a_1b_2-b_1a_2}, y=\frac{a_1c_2-a_2c_1}{a_1b_2-b_1a_2} x=a1b2b1a2c1b2c2b1,y=a1b2b1a2a1c2a2c1
所以这道题只需要读入
a 1 , a 2 , b 1 , b 2 , c 1 , c 2 a_1,a_2,b_1,b_2,c_1,c_2 a1,a2,b1,b2,c1,c2
的值然后根据上述公式输出即可

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _for(i, a, b) for(int (i)=(a);i<(b);i++)
#define _f0r(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}

int main() {
//    freopen("data9.in","r",stdin);
//    freopen("data9.out","w",stdout);
    double a1,a2,b1,b2,c1,c2;
    read(a1), read(b1), read(c1);
    read(a2), read(b2), read(c2);
    //cout<<a1<<b1<<c1<<a2<<b2<<c2;
    printf("%0.2f %0.2f",((b2*c1-b1*c2)/(a1*b2-a2*b1)),((a1*c2-a2*c1)/(a1*b2-a2*b1)));
}

题目二:数字统计

我们以123为例子,对123以十取模后可以得到它的个位为1,然后再将它除以10之后可以得到12,即可以去掉它的个位,重复以上操作就可以得到它每个位数的值。然后再将每位上的值与所给的值进行比较,如果相同就将结果加1。对于范围内的数字,只需要对每个数字进行以上操作,之后将结果加在一起即可。

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _for(i, a, b) for(int (i)=(a);i<(b);i++)
#define _f0r(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}

int main() {
//    freopen("data9.in","r",stdin);
//    freopen("data9.out","w",stdout);
    int l,r,n,ans=0;
    read(l);read(r), read(n);
    _f0r(i,l,r){
        int t=i;
        do{
            if(t%10==n)//对每一位进行判断
                ans++;
            t/=10;
        }while(t);
    }
    cout<<ans;
    return 0;
}

题目三:荔枝食不食

此题改编自猴子吃桃问题

对于这道题,我们需要从后往前推,由于第m天只剩下一个荔枝,所以第(m-1)天剩下(1+1)*2个荔枝,第(m-2)天剩下((1+1)*2+1)*2个荔枝…………以此反复推到第一天就可以得到第一天摘了多少个荔枝了

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _for(i, a, b) for(int (i)=(a);i<(b);i++)
#define _f0r(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}

int main() {
//    freopen("data9.in","r",stdin);
//    freopen("data9.out","w",stdout);
  ll day,x1=1;
  read(day);
  while (day){
      x1=(x1+1)*2;//前一天的荔枝数是今天荔枝数加1后的两倍
      day--;
  }
  cout<<x1;
}

题目四:删除数字

这道题是一道考察贪心算法的简单题

对于一个数字如175438,如果我们需要删掉4个数字,那么我们需要删掉高位比低位小的数字,如十万位的1和万位的7由于1比7小所以需要把1删掉,这样得到的数值才是最大的,同理8前面的5、4、3比它小,所以剩下的三个数我们应该选择删除5、4、3,这样得到的78是删掉数字后最大的。还有一种情况,如54321删掉4个数字,如果我们通过上面的操作,我们无法删掉任何数字,所以要把最后的四个数,即4321删除,得到一位最大的数5,由于k<=N;所以存在删掉后一个数字都不剩的情况,这时候我们要补个0。

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _fo(i, a, b) for(int (i)=(a);i<(b);i++)
#define _FO(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}
int k;
void del(string*a,int len){
 string n=*a;
 for (int i = 1;n.length()>len&&i<n.length() ; i++) {
     if(i==0)
         continue;
     if(n[i-1]<n[i]&&n.length()>len){//当长度小于len时不进行操作
         n.erase(i-1,1);//如果高位比低位小去掉高位
         i-=2;
     }
 }
 *a=n;
}
int main(){
 //freopen("data0.in","r",stdin);
 //freopen("data0.out","w",stdout);
 string n;
 cin>>n>>k;
 int len=(int)n.length()-k;
 del(&n,len);
 if(n.length()>len)//删除后数字的长度大于题目所要求的长度,要把后面几位删除
     n.erase(len,n.length()-len);
 if(n.length()==0)
     n.push_back('0');//当长度为零时,对结果补零
 cout<<n;
 return 0;
}

题目五:字符串匹配

这 题 数 据 的 范 围 为 1 0 6 , 对 于 B F 算 法 最 坏 的 时 间 复 杂 程 度 为 1 0 12 , 是 无 法 通 过 本 题 的 , 因 此 本 题 需 要 使 用 K M P 算 法 或 者 其 他 更 高 效 的 算 法 。 这题数据的范围为 10^6 , 对于BF算法最坏的时间复杂程度为 10^{12},是无法通过本题的,因此本题需要使用KMP算法或者其他更高效的算法。 106BF1012使KMP

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _fo(i, a, b) for(int (i)=(a);i<(b);i++)
#define _FO(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}
int next_[100000005];
void InitNext(string s){
    int j=-1;
    next_[0]=-1;
    for (int i = 1; i < s.length(); ++i) {
        while (j>-1&&s[j+1]!=s[i])
            j=next_[j];
        if(s[j+1]==s[i])
            j++;
        next_[i]=j;
    }
}
bool KMP(string s,string s1,int pos){
    int j=-1;
    bool flag= false;
    for (int i = 0; i < s.length(); ++i) {
        while (j>-1&&s1[j+1]!=s[i])
            j=next_[j];
        if(s1[j+1]==s[i])
            j++;
        if(j==s1.length()-1){
            cout<< i-j+1<<endl;
            flag= true;
        }
    }
    return flag;
}
int main() {
    //freopen("data9.in","r",stdin);
    //freopen("data9.out","w",stdout);
    string s,find;
    cin>>s>>find;
    InitNext(find);
    bool n=KMP(s,find,0);
    if(!n)
        {
            cout<<-1<<endl;
        }
}

题目五:砝码称重

我们先考虑不去掉砝码的情况

这道题如果不去掉砝码的话是一道01背包问题

对于每个砝码,我们可以选择把它放在天平的左边、右边或者不放,如1 3 3

我们从第一个砝码开始看,对于放在左边、右边、不放可以称出1,-1,0的重量,再选完一个的基础上对第二个砝码进行选择,对于放在左边、右边、不放可以称出4,3,2,1,0,-1,-2,-3,-4的重量,再选两个的基础上选第三个可以称出7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7的重量

那对于去掉砝码又应该怎么办呢?

只要选择去掉砝码后对剩下的砝码进行上面的的操作就可以得出砝码可以称的重量,对所有去掉砝码的情况进行上述操作就可以得到每种情况可以称重的数量,之后对这些值进行比较选出最大的值即为该题的答案

如何得到所有情况呢?

可以使用dfs算法,对每个进行砝码进行选择是否使用,如果使用,则对下一个砝码进行选择;如果不使用,则将弃选数量加一后再对下一个砝码进行选择。选到最后一个砝码时,如果弃选数量等于题目所给的数量则进行一次dp操作。

下面是本题题解C++代码,题目解法不唯一,供大家交流参考

#include <bits/stdc++.h>

#define _fo(i, a, b) for(int (i)=(a);i<(b);i++)
#define _FO(i, a, b) for(int (i)=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template<typename T>
inline void read(T&x) { x = 0;bool flag = true;char c = (char) getchar();while (c < '0' || c > '9') {if (c == '-')flag = false;c = (char) getchar();}while (c >= '0' && c <= '9') {x = x*10+(c^48);c = (char) getchar();}if(c=='.'){double s=0.1;c=(char ) getchar();while (c >= '0' && c <= '9') {x = x + (c ^ 48)*s;c = (char) getchar();s*=0.1;}}x= (flag ? x : -x);}
int a[25],m,n,fans,b[25];
bool chose[25],f[25][4020];
void dp(){
    int ans=0,total=0;
    fill(f[0],f[24], false);
    _FO(i,0,n)
    f[i][2010]= true;
    for (int i = 1; i <= n-m; ++i) {
        total+=b[i];
        for (int j = 2010-total; j <=2010+total ; ++j) {
            if((j-b[i]>=0&&j+b[i]<=4020)&&(f[i-1][j-b[i]]||f[i-1][j+b[i]]||f[i-1][j]))
                f[i][j]= true;//可以称到的重量标记为true
        }
    }
    for (int j = 2011; j <= 2010+total; ++j) {
        if(f[n-m][j]) {
            ans++;//对结果进行统计
        }
    }
    fans= max(fans,ans);
}
void dfs(int now,int drop){
    if(drop>m)
        return;
    if(now==n+1){
        if(drop==m) {
            int x=1;
            _FO(i,1,n){
                if(!chose[i])
                    b[x++]=a[i];//选择符合条件的结果
            }
            dp();
        }
        return;
    }
    dfs(now+1,drop);
    chose[now]= true;//不选进行标记
    dfs(now+1,drop+1);
    chose[now]= false;//执行dfs后进行回溯
}
int main() {
//    freopen("data9.in","r",stdin);
//    freopen("data9.out","w",stdout);
    read(n), read(m);
    for (int i = 1; i <= n; ++i) {
        read(a[i]);
    }
    dfs(1,0);
    cout<<fans;
}

题解思路&代码来源:o0kangkang0o
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫_0329

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值