从易到难,总体来说,这次的小白月赛我认为是比较正常的了,没有考什么高深的算法,基本都是基本功

H题:神奇的字母(二)

签到题:哈希。注意不是输入一行而是多行
思路:对于每输入的一行单独处理,我们输入一行后,遍历每个字符,然后用mx(初始为-1)记录当前已知的出现最多的字符的个数,用key记录出现最多的字符,每遍历一个字符的时候,我们用哈希记录目前为止这个字符出现的个数,同时与mx比较,若大于mx,则key指向当前这个字符。
代码:

#include<bits/stdc++.h>
using namespace std;
int has[300];
int main(){
    string s;
    char key;
    int mx=-1;
    while(cin>>s){
        int len=s.length();
        for(int i=0;i<len;i++){
            has[s[i]]++;
            if(has[s[i]]>mx){
                mx=has[s[i]];
                key=s[i];
            }
        }
    }
    cout<<key<<endl;
    return 0;
}

F题:疯狂的自我检索者

思路:也是签到题,应该很容易就能想到,我们的m个人的分数分别位1,5,然后求平均数即可。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100010];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    double ans=0;
    for(int i=0;i<n-m;i++){
        int k;
        scanf("%d",&k);
        ans+=k;
    }
    double res=ans+m;
    res/=n;
    printf("%.5lf ",res);
    res=ans+m*5;
    res/=n;
    printf("%.5lf\n",res);
    return 0;
}

E题:点击消除

思路:当天刚好牛客比赛之前有个cf的比赛,而cf的B题我认为是和这题的思路都是一样的,所以比较快就做出了。我们先定义一个string字符串c,我们可以发现,对于连续的字符,如果它连续的个数为奇数个,那么消除后只能留下一个字符,那么就让这个字符加到c的后面去(就仅仅对这段连续的字符考虑,不考虑消除之后还存在连续)如果为偶数,那么就不剩下了,那么c就不加这个字符,当所有遍历完之后,我们继续对判断c里面是否还有连续的相同字符,如果有,则执行同样的操作,否则结束这个循环,但还要注意的是最后的c字符串是否为空串,如果为空串,则输出0,否则输出最后所得的字符串即可。
代码:

#include<bits/stdc++.h>
using namespace std;
bool judge(string c){
    int len=c.length();
    for(int i=1;i<len;i++){
        if(c[i]==c[i-1])  return true;
    }
    return false;
}
int main(){
    string s;
    cin>>s;
    while(judge(s)){
        int len=s.length();
        int k=1;
        string c;
        for(int i=1;i<len;i++){
            if(s[i]!=s[i-1]){
                //cout<<s[i-1]<<endl;
                //cout<<"k:"<<k<<endl;
                if(k&1)  c+=s[i-1];
                k=1;
            }
            else k++;
        }
        if(k&1)  c+=s[len-1];
        s=c;
        //cout<<c<<endl;
    }
    if(s.length()!=0)  cout<<s<<endl;
    else cout<<"0"<<endl; 
    return 0;
}

A题:AOE还是单体?

思路:简单贪心。我们可以发现,对于蛮牛践踏,我们需要x的mp,而如果有这x个mp,我们可以对x个怪物的造成1的伤害,所以,我们如果当前还存活的怪物数小于x个,那么不用群体技能,否则,用蛮牛践踏显然是最合适的。但这里要注意的是,如果一开始的怪物数小于x个,那么ans就是总的怪物的血量。否则,我们对这n个怪物的血量进行排序,我们找到血量第x大的怪物的血量,假如为k,然后,我们想要消耗最小的话,那么就需要使用k*x的mp,然后,只需要遍历x+1到n的怪物的血量,对于每个i,我们还需要单独使用a[i]-k的mp,累加即可得ans。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200010];
bool cmp(int a,int b){
    return a>b;
}
int main(){
    int n,x;
    cin>>n>>x;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    ll ans=0;
    sort(a+1,a+1+n,cmp);
    if(n<x){
        for(int i=1;i<=n;i++)  ans+=a[i];
        cout<<ans<<endl;
        return 0;
    }
    int temp=a[x];
    ans+=temp*x;
    for(int i=1;i<x;i++){
        ans+=(a[i]-temp);
    }
    cout<<ans<<endl;
    return 0;
}

I题:十字爆破

思路:这题,我们发现我们不知道n,m的具体的范围,如果要开二维数组,那么每个维度都要1000000,显然是不可行的,怎么办呢?我们发现,我们要求出每个位置的下一步的数,那么就是这行的所有的数之和加上这一列的所有的数字之和再减去当前的这个元素的大小就是了,我们发现开二维数组的目的无非是为了保存每个位置上的元素,并不和每个位置有多大的关联,所以,这里有个技巧就是用以一维的数组替代二维的数组存储元素,因为我们输入的顺序和我们输出的顺序是一样的,这是没有影响的,同时,我们记录每一行和每一列的元素之和。最后按输入的顺序处理后输出即可。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll hang[1000010],lie[1000010],b[1000010];
int main(){
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    int n,m;
    cin>>n>>m;
    int t=0;
    int a;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            cin>>a;
            hang[i]+=a;
            lie[j]+=a;
            b[t++]=a;
        }
    }
    //for(int i=1;i<=n;i++)  cout<<hang[i]<<endl;
    //for(int j=1;j<=m;j++)  cout<<lie[j]<<endl;
    t=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            ll temp=lie[j]+hang[i]-b[t++];
            cout<<temp;
            if(j<m)  cout<<" ";
        }
        cout<<endl;
    }
    return 0;
}

G题:解方程

思路:简单的二分求解法。没什么思考难度,只是要注意一下精度问题即可。
代码:

#include<bits/stdc++.h> 
#define eps 1e-7
using namespace std;
int a,b,c;
int main(){
    scanf("%d%d%d",&a,&b,&c);
    double l=1,r=1e9,mid;
    while(1){
        mid=(l+r)/2;
        if(abs(pow(mid,a)+b*log(mid)-c)<eps)  break;
        else if(pow(mid,a)+b*log(mid)-c>=eps)  r=mid;
        else  l=mid;
    }
    printf("%.10lf\n",mid);
    return 0;
}

D题:抽卡

思路:逆元+概率。首先我们想到最后的概率就是在每个池里面都抽不到的概率,然后再用1-这个概率就是了,主要的是我们如何求逆元?我们先求出抽不到的概率对应的解,对于每个池子里面的卡,我们发现抽不到的概率就是(a[i]-b[i])/a[i]。然后我们对单个求逆元,由于mod=1e9+7是一个素数,利用费马小定理可以得到a[i]模mod的逆元就是图片说明 模mod的值。而图片说明可以利用矩阵快速幂来求,最后求到的是拿不到的ans,只要用mod-ans+1即可(别忘了最后还要再%mod)。
代码:

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll a[100010],b[100010];
ll power(ll x,ll y){
    if(y==0)  return 1;
    if(y&1){
        return x*power(x,y-1)%mod;
    }
    else{
        ll mul=power(x,y/2);
        return mul*mul%mod;
    }
}
ll inverse(ll x){
    return power(x,mod-2);
}
int main(){
    ll n;
    cin>>n;
    for(int i=1;i<=n;i++)  cin>>a[i];
    for(int i=1;i<=n;i++)  cin>>b[i];
    ll ans=1;
    for(int i=1;i<=n;i++){
        ll temp1=(a[i]-b[i]);
        ll temp2=inverse(a[i]);
        ans=ans*temp1%mod*temp2%mod;
    }
    ans=mod-ans+1;
    cout<<ans%mod<<endl;
    return 0;
}