牛客周赛 Round 35

比赛地址

A. 小红的字符串切割

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string str;
    cin>>str;
    int len=str.length();
    cout<<str.substr(0,str.length()/2)<<'\n';
    cout<<str.substr(len/2);
}

B. 小红的数组分配

对原数组排序之后看每种数字的出现次数是否为偶数

#include <bits/stdc++.h>
using namespace std;
int v[200010];
int main()
{
    int n;
    cin>>n;
    n*=2;
    vector<int> a(n*2);
    for(int i=1;i<=n;i++) cin>>v[i];
    sort(v+1,v+n+1);
    bool succ=true;
//     for(int i=1;i<=n;i++) cout<<v[i]<<' ';
//     cout<<'\n';
    for(int i=1,j=2;j<=n;i+=2,j+=2) {
        if(v[i]==v[j]) {
            a[j/2]=v[i];
        } else {
            succ=false;
        }
    }
    if(succ) {
        for(int i=1;i<=n/2;i++)
            cout<<a[i]<<' ';
        cout<<'\n';
        for(int i=1;i<=n/2;i++)
            cout<<a[i]<<' ';
    } else {
        cout<<-1<<'\n';
    }
    return 0;
}

C. 小红关鸡

双指针,右指针不断向后移动,在保持两指针之间距离不超过 k 的前提下计算鸡窝个数最大值,个数越大概率越大。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    ll n,k;
    cin>>n>>k;
    vector<ll> v(n);
    for(int i=0;i<n;i++) cin>>v[i];
    sort(v.begin(),v.end());
    ll left=0,right=0;
    ll mx=0;
    while(right<=n) {
        mx=max(mx,right-left+1);
        right++;
        while(v[right]-v[left]>k) left++;
    }
    cout<<((double)mx/n)<<'\n';
    return 0;
}

D. 小红的排列构造

读入数字时做处理

  • 当数字 x 大小超过 n ,直接记录下当前位置,x 不用记录
  • 当 x 第一次出现时,标记 x
  • 当 x 出现且被标记过,说明出现了不止一次,记下当前位置
    对于所有记下的位置和 1 ~ n 中没有出现过的数字,对应输出即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool st[100010];
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin>>n;
    vector<int> v;
    for(int i=0;i<n;i++) {
        ll x;
        cin>>x;
        if(x>n||st[x]) v.push_back(i);
        else st[x]=true;
    }
    
    ll idx=0;
    cout<<v.size()<<'\n';
    for(int i=1;i<=n;i++) {
        if(st[i]==false) {
            cout<<(v[idx++]+1)<<' '<<i<<'\n';
        }
    }
    return 0;
}

E. 小红的无向图构造

给出 n 个点,若要形成图,则至少需要 n - 1 个节点,维护每个距离的点的集合,对于距离为 i 的集合,集合中的每个点至少与上一层(距离为 i - 1)集合中某个点之间存在一条边,最少需要构造的边为当前集合中点的个数。若边还有剩余,可以向上一层多连边,或者本层点之间互相连边。
在这里插入图片描述
红色-必须要连的边
绿色-本层向上一层可以连的更多的边
黄色-本层节点之间可以连多余的边
当出现以下情况时,说明无解

  • 边数量不足 n-1
  • 边数量过多
  • 节点距离出现断层,如0 1 1 3 3
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
vector<int> v[100010]; // 存上一层的点
vector<pii> ans;
map<int,int> mp;
ll n,m;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n>>m;
    vector<pii> a(n);
    for(int i=0;i<n;i++) {
        ll v;
        cin>>v;
        mp[v]++;
        a[i]={v,i+1};
    }
    sort(a.begin(),a.end());
    ll mne=0,last=-1; // 最少需要的边
    bool flag=true;
    for(auto [x,y]:mp) { // x-点的编号,y-点的数量
        if(x!=last+1) {
            flag=false;
            break;
        } else {
            if(last!=-1) mne+=y;
        }
        last=x;
    }
    
    flag=flag&&(mne<=m);
    if(flag) {
        ll more=m-mne;
        for(int i=0;i<n;i++) {
            v[a[i].first].push_back(a[i].second);
        }
        for(int i=1;i<n;i++) {
            for(int j=0;j<v[i].size();j++) {
                ans.push_back({v[i-1][0],v[i][j]});
            }
            if(more) {
                for(int k=1;k<v[i-1].size();k++) {
                    for(int j=0;j<v[i].size();j++) {
                        ans.push_back({v[i-1][k],v[i][j]});
                        more--;
                        if(more==0) break;
                    }
                    if(more==0) break;
                }
            }
            if(more) {
                for(int j=0;j<v[i].size();j++) {
                    for(int k=j+1;k<v[i].size();k++) {
                        ans.push_back({v[i][j],v[i][k]});
                        more--;
                        if(more==0) break;
                    }
                    if(more==0) break;
                }
            }
        }
        if(more) {
            cout<<-1;
        } else {
            for(auto [x,y]:ans) {
                cout<<x<<' '<<y<<'\n';
            }
        }
    } else {
        cout<<-1;
    }
}

F、G. 小红的子序列权值和

看了大佬的题解点我

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll fact[100010],infact[100010],number[4];
ll n;
ll qmi(ll a,ll b)
{
    ll res=1;
    while(b) {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void init(int n)
{
    fact[0]=infact[0]=1;
    for(int i=1;i<=n;i++) {
        fact[i]=fact[i-1]*i%mod;
        infact[i]=(ll)infact[i-1]*qmi(i,mod-2)%mod;
    }
}
ll c(ll n,ll m)
{
    if(m<0||n-m<0) return 0;
    return fact[n]*infact[m]%mod*infact[n-m]%mod;
}
ll getsum(ll x)
{
    ll res=0;
    for(int i=0;i<=x;i++) {
        res+=c(x,i)*(i+1)%mod;
        res%=mod;
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n;
    init(n);
    while(n--) {
        int x;
        cin>>x;
        number[x]++;
    }
    ll ans=getsum(number[2])*getsum(number[3])%mod;
    ans=ans*qmi(2,number[1])%mod;
    ans--;
    cout<<ans<<'\n';
    return 0;
}
  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值