2019蓝桥杯初赛


最大降雨量

题意:

给1到49这49个数字,要求分成7组,每组7个数字,每组的得分是每组的中位数。
总得分是每组得分的中位数,现在你可以决定如何分组,问最优情况下最大得分是多少。

思路:

一共7组,总得分是每组得分的中位数,那么得分最小的三组是没用的,贪心地用最小的21个数去填:1到21。
对于剩下的4组,每组的得分是中位数,因此每组中最小的三个数是没用的,贪心地用剩下的最小的12个数去填:22到33
那么最后的总得分就是剩下的最小的数:34


Fibonacci数列与黄金分割

题意:

在这里插入图片描述
n<=2e9

思路:

第一眼看到数据范围还以为是矩阵快速幂,然后发现题目没有取模,要是真算出来答案肯定是大数。
其实题目已经提醒了比值会趋近黄金分割。
打表发现当n大于20的时候,f(n)/f(n+1)都是0.61803399,只需要计算斐波那契数列的1到21项的就行了。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e4+5;
int f[maxm];
signed main(){
    f[1]=f[2]=1;
    for(int i=3;i<=21;i++){
        f[i]=f[i-1]+f[i-2];
    }
    int n;
    cin>>n;
    if(n>=20){
        n=20;
    }
    printf("%.8f\n",f[n]*1.0/f[n+1]);
    return 0;
}

年号字串

题意:

小明用字母A 对应数字1,B 对应2,以此类推,用Z 对应26。对于27以上的数字
小明用两位或更长位的字符串来对应,例如AA 对应27,AB 对应28,AZ 对应52,LQ 对应329。
请问2019 对应的字符串是什么?

思路:

咋一看好像是26进制,但是很快发现题目里面不是0到25,而是1到26。
发现当某个位为26的时候(即模26等于0的时候),不让这个位进位,把他从0改成26就行了。
这样就从正常的0到25改成了1到26,分别对应A到Z
其他步骤和正常的进制转换差不多
最后计算出答案为BYQ

code:

#include<bits/stdc++.h>
using namespace std;
signed main(){
    stack<char>q;
    int n=2019;
    while(n){
        int t=n%26;
        if(t==0){
            q.push('Z');
            n-=26;//少掉一个进位,这里改成减1也可以,效果是一样的
        }else{
            q.push('A'+t-1);
        }
        n/=26;
    }
    while(!q.empty()){
        cout<<q.top();
        q.pop();
    }
    return 0;
}

后缀表达式

题意:

在这里插入图片描述

思路:

先给一个例子:
0 2
1 2 3
最优解是3 1 2 - -,这个后缀表达式转化为中缀就是3-(1-2),答案为4。

这个例子是为了说明对于这道题目来说,可以在任意位置加括号。

如果没有负号,则答案就是所有数的和。

下面考虑有负号的情况。
因为可以加括号,那么就可以用一个负号把其他一堆负数的和直接变成正数,因此可以直接把负数变成正数。
但是要考虑特殊情况:
1.当所有数都是负数时,因为需要一个数作为被减数,因此会有一个负数不能变正数,贪心地让绝对值最小的负数不变正。
2.当所有数都是正数时,因为至少要有一个负号起作用,因此必须减去一个数,贪心地减去最小的正数。
至少要有一个负号起作用的例子:x-(y-z),不管怎么排都要减去括号中的一个数

ps:
感觉分类出的细节挺多的,很容易翻车。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
int a[maxm];
int n,m;
signed main(){
    cin>>n>>m;
    int len=n+m+1;
    int e=0;//记录负数的个数
    int ans=0;
    for(int i=1;i<=len;i++){
        cin>>a[i];
        if(a[i]<0)e++;
        ans+=a[i];
    }
    if(m){//如果有负号
        sort(a+1,a+1+len);
        if(e){//如果有负数
            if(e==len){//如果全是负数,那么只有一个负数不会被变成正数
                for(int i=1;i<=len-1;i++){
                    ans-=a[i]*2;
                }
            }else{//否则所有负数都可以变成正数
                for(int i=1;i<=e;i++){
                    ans-=a[i]*2;
                }
            }
        }else{//如果没有负数,因为至少减去一个数,因此贪心地减去最小的
            ans-=a[1]*2;
        }
    }
    cout<<ans<<endl;
    return 0;
}

外卖店优先级

题意:

在这里插入图片描述

思路:

1e5的数据范围,如果直接按时间模拟肯定超时。
因为物品最多1e5个,而且每家店不影响其他店,因此可以考虑对于每家店单独模拟。
模拟的时候注意操作顺序。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
vector<int>g[maxm];
int mark[maxm];
int a[maxm];
signed main(){
    int n,m,T;
    cin>>n>>m>>T;
    for(int i=1;i<=m;i++){
        int ts,id;
        cin>>ts>>id;
        g[id].push_back(ts);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        sort(g[i].begin(),g[i].end());
        int last=0;
        int now=0;
        int ok=0;
        for(int v:g[i]){
            if(v==last){//同一时间多个订单的情况
                now+=2;
                if(now>5)ok=1;
            }else{
                now-=(v-1)-last;
                if(now<0)now=0;
                if(now<=3)ok=0;//这个要先判断然后再+2
                now+=2;
                if(now>5)ok=1;
                last=v;
            }
        }
        now-=T-last;
        if(now<0)now=0;
        if(now<=3)ok=0;
        if(ok)ans++;
    }
    cout<<ans<<endl;
    return 0;
}

糖果

题意:

在这里插入图片描述

思路:

n最大100,m最大20,直接二进制枚举或者dfs肯定不行。
发现m最大20,在可状压范围内,考虑用状压dp来解决。
令d(sta)为到达状态sta需要购买的最小包数,遍历每包糖果更新即可。
初始状态下d(0)=0。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=105;
int a[maxm];
int d[1<<21];
int n,m,k;
signed main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        int now=0;
        for(int j=1;j<=k;j++){
            int x;
            cin>>x;
            x--;
            now|=(1<<x);
        }
        a[i]=now;
    }
    for(int i=0;i<(1<<m);i++){
        d[i]=1e9;
    }
    d[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<(1<<m);j++){
            if(d[j]>=n)continue;//实测这里剪一下可以快好多
            d[j|a[i]]=min(d[j|a[i]],d[j]+1);
        }
    }
    int ans=d[(1<<m)-1];
    if(ans==1e9)ans=-1;
    cout<<ans<<endl;
    return 0;
}

RSA解密

题意:

在这里插入图片描述

思路:

因为C,n已知,因此计算出e就可以得到X了。

由于n已知,且已知n只有两个质因子p和q,因此可以在本地用试除法计算出p和q的值。
通过计算得出p=891234941,q=1123984201。

题目已知d乘e再除以(p-1)(q-1)的余数为1,(p-1)(q-1)现在是已知的,设为k,本地计算出k=1001733991047948000。
则d e≡1(mod k),左右同时乘上d在模k意义下的逆元d-1,式子变为e≡d-1(mod k)
问题就转化为了计算d在模k意义下的逆元。

这里要知道欧拉定理:
设m是一个正整数,a是一个整数且gcd(a,m)=1,那么aφ(m)≡1(mod m)

因为题目已知d与(p-1)(q-1)互质,即d与k互质,因此dφ(k)≡1(mod k),那么d*dφ(k)-1≡1(mod k)。
得出d在模k意义下的逆元为dφ(k)-1,计算出φ(k)-1之后配合快速幂即可计算出d的逆元,即e。

本地计算出φ(k)为267048288597043200。

因为计算dφ(k)-1的时候,模数k比较大,乘法会爆longlong,所以还需要快速乘。
计算出dφ(k)-1=823816093931522017LL。

然后直接根据题目的式子X=Ce mod n 就能计算出X了。
计算出X=579706994112328949。

要用的函数和计算出的值挂在代码里面了。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int mul(int a,int b,int mod){//快速乘
    int ans=0;
    while(b){
        if(b&1){
            ans=(ans+a)%mod;
        }
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
int ppow(int a,int b,int mod){//快速幂
    int ans=1%mod;
    while(b){
        if(b&1){
            ans=mul(ans,a,mod);
        }
        a=mul(a,a,mod);
        b>>=1;
    }
    return ans;
}
int phi(int n){//计算欧拉函数
    int ans=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            ans=ans/i*(i-1);
            while(n%i==0)n/=i;
        }
    }
    if(n>1)ans=ans/n*(n-1);
    return ans;
}
int getprime(int n){//试除法
    for(int i=2;i*i<=n;i++){
        if(n%i==0)return i;
    }
    return 1;
}
signed main(){
    int n=1001733993063167141LL;
    int d=212353;
    int C=20190324;
    //
    int p=891234941;//p=getprime(n)
    int q=1123984201;//q=n/p
    int k=1001733991047948000LL;//k=(p-1)*(q-1)
    int phik=267048288597043200LL;//phik=phi(k)
    int invd=823816093931522017LL;//invd=ppow(d,phik-1,k)
    int e=invd;
    int X=579706994112328949LL;//X=ppow(C,e,n);
    cout<<X<<endl;
    return 0;
}

发布了430 篇原创文章 · 获赞 36 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/104959288