第七章 数学

1049.1的个数

在这里插入图片描述

  • 详细见算法基础数位统计DP
#include<iostream>
#include<vector>

using namespace std;

int cal(int n){
    
    int res=0;
    
    vector<int> num;
    
    while(n)num.push_back(n%10),n/=10;
    
    for(int i=num.size()-1;i>=0;i--){
        
        int d=num[i];
        
        int abc=0,def=0,power=1;
        
        for(int j=i-1;j>=0;j--){
            
            def=def*10+num[j];
            
            power*=10;
        }
        
        for(int j=num.size()-1;j>=i+1;j--)abc=abc*10+num[j];
        
        if(d==0)res+=abc*power;
        
        else if(d==1)res+=abc*power+def+1;
        
        else res+=(abc+1)*power;
    }
    
    return res;
}

int main(){
    
    int n;
    
    cin>>n;
    
    cout<<cal(n);
}

1059.质因子

在这里插入图片描述

  • 按序枚举质因子,由于合数会被小于他的质因子提前筛掉,所以不会出现在最终答案
  • 复杂情况见算法基础筛质数
#include<iostream>
#include<cstring>
#include<vector>

using namespace std;

int main(){
    
    int n;
    
    cin>>n;
    
    cout<<n<<"=";
    
    string res;
    
    if(n==1){
        
        cout<<1;
        
        return 0;
    }
    
    for(int i=2;i<=n/i;i++){
        
        int sum=0;
        
        while(n%i==0)sum++,n/=i;
        
        if(sum==1)res+=to_string(i)+"*";
        
        else if(sum>1) res +=to_string(i)+"^"+to_string(sum)+"*";  
    }
    
    if(n>1)res+=to_string (n);
    
    else res.erase(res.size()-1);
    
    cout<<res;
}

1081.有理数的和

在这里插入图片描述

  • 这道题范围较大,时刻注意对计算结果的化简
  • 利用欧几里得算法对分子分母进行化简
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>

using namespace std;

typedef long long LL;

LL  gcd(LL a,LL b){
    
    return b? gcd(b,a%b) : a;
}

int main(){
    
    int n;
    
    cin>>n;
    
    LL a=0,b=1;           //分子和,分母和
    
    for(int i=0;i<n;i++){
        
        LL c,d;         //当前分子分母;
        
        scanf("%lld/%lld",&c,&d);
        
        LL t =gcd(c,d);
        
        c/=t,d/=t;         //分子分母同除最大公约数,使当前数最简
        
        t=gcd(b,d);
        
        a=d/t*a+b/t*c;     //做最简加法,避免溢出
        
        b=b/t*d;
        
        t=gcd(a,b);      //化简
        
        a/=t,b/=t;
    }
    
    if(a>=b){
        
        cout<<a/b;
        
        if(a%b)cout<<" "<<a%b<<"/"<<b;
    }
    
    else if(a)cout<<a<<"/"<<b;
    
    else cout<<0;
}

1088.有理数运算 **

在这里插入图片描述

  • 这题处理输入输出都挺恶心的,思路和上题一致
#include<iostream>
#include<cstring>
#include<vector>

using namespace std;

typedef long long LL;

LL gcd(LL a,LL b){
    
    return b ? gcd(b,a%b) : a;
}

void print(LL a,LL b){
    
    LL t = gcd(a,b);
    
    a/=t,b/=t;
    
    if(b<0)a*=-1,b*=-1;      
    
    bool is_minus=a<0;
    
    if(is_minus)cout<<"(";
    
    if(b==1)cout<<a;           //当答案为整数时,直接输出
    
    else {
        
        if(abs(a)>=b)cout<<a/b<<" "<<abs(a)%b<<"/"<<b;      //答案为假分数
        
        else cout<<a%b<<"/"<<b;                             //答案为真分数
    }
    
    if(is_minus)cout<<")";
}

void add(LL a,LL b,LL c,LL d){
    
    print(a,b),cout<<" + ",print(c,d),cout<<" = ";

    a=a*d+b*c;

    b=b*d;
    
    LL t=gcd(a,b);
    
    a/=t, b/=t;
    
    print(a,b),cout<<endl;
}

void sub(LL a,LL b,LL c,LL d){
    print(a,b),cout<<" - ",print(c,d),cout<<" = ";
    
    a=a*d-b*c;
    
    b=b*d;
    
    LL t=gcd(a,b);
    
    a/=t, b/=t;
    
    print(a,b),cout<<endl;
}

void mul(LL a,LL b,LL c,LL d){
    
    print(a,b),cout<<" * ",print(c,d),cout<<" = ";
    
    a=a*c;
    
    b=b*d;
    
    LL t=gcd(a,b);
    
    a/=t, b/=t;
    
    print(a,b),cout<<endl;
}

void div(LL a,LL b,LL c,LL d){
    
    print(a,b),cout<<" / ",print(c,d),cout<<" = ";
    
    if(!c)cout<<"Inf";
    
    else {
        
        a=a*d;
    
        b=b*c;
        
        LL t=gcd(a,b);
        
        a/=t, b/=t;
        
        print(a,b),cout<<endl;
    }
}

int main(){
    
    LL a,b,c,d;
    
    scanf("%lld/%lld %lld/%lld",&a,&b,&c,&d);
    
    add(a,b,c,d);
    
    sub(a,b,c,d);
    
    mul(a,b,c,d);
    
    div(a,b,c,d);
}

1096.连续因子

在这里插入图片描述

  • 枚举起始位置,对于每个起始位置,枚举最大乘积序列长度
#include<iostream>
#include<vector>

using namespace std;

int main(){
    
    int n;
    
    cin>>n;
    
    vector<int>res;
    
    for(int i=2;i<=n/i;i++)
       
       if(n%i==0){
           
           vector<int> seq;
           
           for(int m=n,j=i;m%j==0;j++){
               
               m/=j;
               
               seq.push_back(j);
           }
           
           if(seq.size()>res.size())res=seq;
       }
       
    if(!res.size())res.push_back(n);
    
    cout<<res.size()<<endl;
    
    cout<<res[0];
    
    for(int i=1;i<res.size();i++)cout<<"*"<<res[i];
}

1103.整数分解 **(二维背包)

在这里插入图片描述

  • 简化为二维背包问题f[i][j][k]
  • 分析:物品序号1,2,3...x(x<= ^p√N),物品体积1^p,2^p,3^p....x^p
    各个物品重量均为1
  • 最后要求体积和恰好为n,数量恰好为s序号和的最大值

在这里插入图片描述

  • 由于最后求得的状态转移方程不能得到具体选择的方案,我们要回推整个方案选择过程
  • 观察状态转移方程f[i,j,k]=max(f[i-1,j,k],f[i,j-i^p,k-1]+i)可以发现,我们每次从选择i物品和不选i物品两种状态之一发生转移,而题目要求在满足最大序号和的情况下,选择物品字典序越大越好,也就是优先考虑从状态f[i,j-i^p,k-1]+i转移
#include<iostream>
#include<cstring>

using namespace std;

const int N=410;

int f[21][N][N];

int power(int a,int b){
    
    int res=1;
    
    while(b)res*=a,b--;
    
    return res;
}

int main(){
    
    int n,s,p;
    
    cin>>n>>s>>p;
    
    memset(f,-0x3f,sizeof f);  //求最大值,初始化为负无穷
    
    f[0][0][0]=0;
    
    int i;                   //dp过程中,找到序号i的最大值
    
    for(i=1; ;i++){
        
        int v= power(i,p);
        
        if(v>n)break;
        
        for(int j=0;j<=n;j++)
        
           for(int k=0;k<=s;k++){
               
               f[i][j][k]=f[i-1][j][k];
               
               if(j>=v && k)f[i][j][k]=max(f[i][j][k],f[i][j-v][k-1]+i);    //满足体积容量大于v,物品数目至少为1时,可以发生转移
           }
    }
    
    i--;          //还原i最大值
    
    
    if(f[i][n][s]<0)cout<<"Impossible"<<endl;
    
    else{                                 //倒推
        
        cout<<n<<" = ";
        
        bool is_first=true;
        
        while(i){
            
            int v=power(i,p);
            
            while(f[i][n-v][s-1]+i>=f[i-1][n][s]){     //只要能够从优先方案转移,就一直选
                
                if(is_first)is_first=false;
            
                else cout<<" + ";
                
                cout<<i<<"^"<<p;
            
                n-=v,s-=1;                              //退回转移来的方案
            }
            
            i--;                                        //无法选择优先方案,退回上一层
        }
        
        
    }
}

1104.数段之和

在这里插入图片描述

  • 前缀和的应用+找规律
  • 这题卡精度,开成long double
#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e5+10;

long double num[N],s[N],c[N];

int main(){

    int n;

    cin>>n;

    s[0]=0;

    c[0]=0;

    long double sum=0;

    for(int i=1;i<=n;i++){

        cin>>num[i];

        s[i]+=s[i-1]+num[i];

        c[i]+=c[i-1]+s[i];     //前缀和的和

        sum+=i*s[i]-c[i-1];    //套娃
    }

    printf("%.2Lf",sum);
}



1112.卡住的键盘

在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>

using namespace std;

unordered_map<char,bool> has;

bool st[210];

bool check(char a){
    
    if( (a>='a' && a<='z') || (a>='0' &&  a<='9'))return true;
    
    else return false;
}

int main(){
    
    int k;
    
    cin>>k;
    
    string s;
    
    cin>>s;
    
    for(int i=0;i<s.size();i++){
        
        if(s[i]!=s[i+1]){
            
            has[s[i]]=true;
            
        }
        
        else {
            
            int len=0;
            
            while(s[i]==s[i+1]){
                
                i++,len++;
            }
            
            len++;
            if(len % k)has[s[i]]=true;
        }
    }
    
    string res;
    
    for(int i=0;i<s.size();i++){
        
        if(!has[s[i]]){
            
            if(!st[s[i]]){
                
                cout<<s[i];
                
                st[s[i]]=true;
            }
            
            res+=s[i];
            
            i+=k-1;
        }
        
        else res+=s[i];
    }
    
    cout<<endl<<res;
    
}

1116.c语言竞赛

在这里插入图片描述

#include<iostream>
#include<cstring>
#include<unordered_map>

using namespace std;

const int N=1e4+10;

unordered_map<string,int> has;

unordered_map<string,bool> st;

bool check(int num){
    
    for(int i=2; i<=num/i;i++){
        
        if(num % i ==0)return false;
    }
    
    return true;
}

int main(){
    
    int n,k;
    
    cin>>n;
    
    for(int i=1;i<=n;i++){
        
        string s;
        
        cin>>s;
        
        has[s]=i;
    }
    
    cin>>k;
    
    while(k--){
        
        string s;
        
        cin>>s;
        
        if(!has[s])cout<<s<<": Are you kidding?"<<endl;
            
        else if(st[s])cout<<s<<": Checked"<<endl;
            
        else{
            
            st[s]=true;
            
            if(has[s]==1)cout<<s<<": Mystery Award"<<endl;
            
            else if(check(has[s]))cout<<s<<": Minion"<<endl;
            
            else cout<<s<<": Chocolate"<<endl;
        }
        
    }
}

1152.谷歌的招聘

在这里插入图片描述


#include<iostream>
#include<cstring>

using namespace std;

bool check(string n){
    
    int num=atoi(n.c_str());
    
    for(int i=2;i<=num/i;i++){
        
        if(num%i==0)return false;
    }
    
    return true;
}

int main(){
    
    int n,k;
    
    cin>>n>>k;
    
    string s;
    
    cin>>s;
    
    bool flag=true;
    
    for(int i=0;i<n-k+1;i++){
        
        string cur=s.substr(i,k);
        
        if(check(cur)){
            
            cout<<cur;
            
            flag =false;
            
            break;
            
        }
    }
    

    if(flag)cout<<"404"<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值