牛客周赛71文字版题解

A.构造 A+B

可以发现 都可以找到一个正整数配对,所以当 时,则有解,否则无解。

void solve(){
    int n,k;
    cin>>n>>k;
    if(n-1>=k){
        cout<<"YES";
    }else{
        cout<<"NO";
    }
}

B.宝石手串

可以把每个字符放进对应的容器,然后比较同一类字母中,相邻两个字母的距离,由于是环,所以需要比较两边的距离,然后取最小值即可。

void solve(){
    int n;
    cin>>n;
    string s;
    cin>>s;
    vector<vector<int>>v(26);
    for(int i=0;i<n;i++) v[s[i]-'a'].push_back(i);
    int ans=1e9;
    for(int i=0;i<26;i++){
        for(int j=1;j<v[i].size();j++){
            ans=min(ans,min(v[i][j]-v[i][j-1]-1,n-(v[i][j]-v[i][j-1]+1)));
        }
        if(v[i].size()>=2){
            ans=min(ans,min(v[i][v[i].size()-1]-v[i][0]-1,n-(v[i][v[i].size()-1]-v[i][0]+1)));
        }
    }
    cout<<(ans==1e9?-1:ans)<<"\n";
}  

C.最小循环节

如果字符串中存在循环节,那么循环节长度一定大于等于字符串中不同字母的个数。

所以只需要找出字符串中不同字母的个数,就可以得到最小循环节长度。

void solve(){
    string s;   
    cin>>s;
    map<char,int>cnt;
    for(auto t:s){
        cnt[t]++;
    }
    cout<<cnt.size();
}

D.气球谜题

只需要全排列枚 个块填的是什么颜色 ,然后枚举每一个位置填什么,下一个位置的颜色可以是当前位置颜色的后面颜色,例如:当前颜色是 ,那么下一个位置的颜色就可以是 ,然后判断一下选定的颜色和下一个位置的颜色是否一致,加上花费时间即可,然后 转移。 这样最后的状态就是第 个位置的最小状态,取最小值即可。

    int n;
    cin >> n;
    string s;
    cin >> s;
    vector<int> a(n);
    for (auto &x : a) {
        cin >> x;
    }

    i64 ans = 1e18;
    vector<int> order{0, 1, 2};
    do {
        vector dp(n + 1,  vector<i64>(3, 1e18));
        dp[0] = {0, 0, 0};
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 3; j++) {
                for (int k = 0; k <= j; k++) {
                    dp[i + 1][order[j]] =  min(dp[i + 1][order[j]], dp[i][order[k]] + (s[i] - '0' != order[j]) * a[i]);
                }
            }
        }
        ans =  min(ans, * min_element(dp[n].begin(), dp[n].end()));
    } while ( next_permutation(order.begin(), order.end()));

    cout << ans << '\n';

E.三角谜题

直接枚举底边,然后寻找一个存在两条相等的边,这个边越长越好,因为面积要越大,高就要越长,也就是斜边要越长。 由于这个暴力寻找从大到小枚举,若边数不满足或者不构成等腰三角形会很快被判完,所以需要寻找的次数很少。

using ld=long double;
ld Heronformula(ld a,ld b,ld c){
    ld p=(a+b+c)/2;
    ld s=sqrt(p*(p-a)*(p-b)*(p-c));
    return s;
}
void solve(){
    int n;
    cin>>n;
    map<i64,i64>cnt;
    for(int i=1;i<=n;i++){
        i64 len,a;
        cin>>len>>a;
        cnt[len]+=a;
    }
    vector<i64>v;
    for(auto t:cnt){
        if(t.second>=2){
            v.push_back(t.first);
        }
    }
    sort(v.begin(),v.end(),greater<i64>());
    ld ans=-1;
    for(auto &t:cnt){
        t.second--;
        for(auto q:v){
            if(cnt[q]>=2&&2*q>t.first){
                ans=max(ans,Heronformula(t.first,q,q));
                break;
            }
            if(2*q<=t.first) break;
        }
        t.second++;
    }
    cout<<fixed<<setprecision(10)<<ans<<"\n";
}

F.变化的数组

首先根据期望的公式,可以得到

那么我们可以枚举 的值,然后计算 ,然后根据公式计算求和得到

因为一个数 操作后,产生的不同数字不超过 个,所以直接枚举变化的次数,那么也就得到这个数变化后的数字,那么这样就得到对这个数操作不超过 次的方案数,当数值将不发生改变时,此数的方案数即是方案总数扣掉数字在此之前的所有组合数方案之和。

由于概率恒定为 ,且操作共 次,所以最后需要乘上 ,此步用逆元做即可。

const int mod =1000000007;
i64 qmi(i64 a, i64 b) {
    i64 ans = 1;
    while (b) {
      if (b & 1)
        ans = ans * a % mod;
      a = a * a % mod;
      b >>= 1;
    }
    return ans;
};
i64 C(i64 a,i64 b){
    i64 ans=1;
    for(int i=a;i>=a-b+1;i--) ans=ans*i%mod;
    for(int j=1;j<=b;j++) ans=ans*qmi(j,mod-2)%mod;
    return ans;
}
void solve(){
    int n,m,k;
    cin>>n>>m>>k;
    vector<i64>a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    i64 ans=0;
    i64 sum=qmi(2,k);
    for(int i=1;i<=n;i++){
        i64 num=a[i];
        i64 x=sum;
        for(int j=0;j<=min(35,k);j++){
            i64 g=C(k,j);
            ans+=num*g%mod;
            ans%=mod;
            x=(x-g+mod)%mod;
            if(!(num&m)) break;
            num=num+(num&m);
        }
        ans+=num*x%mod;
        ans%=mod;
    }
    cout<<ans*qmi(qmi(2,k),mod-2)%mod;
}

全部评论
E怎么算的时间复杂度?感觉这个暴力会O(n2)T
点赞 回复 分享
发布于 2024-12-10 19:03 山东
第四题更是直接砂岩了
点赞 回复 分享
发布于 2024-12-09 19:11 河北
3还好,但是我2竟然写的二分想哭。
点赞 回复 分享
发布于 2024-12-09 19:10 河北
分子大佬第三题这种思维我该怎么练
点赞 回复 分享
发布于 2024-12-08 21:33 广东

相关推荐

饿魔:看到在线简历了吧
点赞 评论 收藏
分享
评论
5
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务