牛客小白月赛117

依旧掉分场, 疯狂wa, 感觉越打越菜了.... 

A. 好字符串 

题目描述
给你一个长度为 n 的字符串 s,如果一个小写字母为好字符,当且仅当该小写字母对应的大写字母和它同时在字符串 s 中出现 或者 同时不在字符串 s 中出现;而如果一个字符串为好字符串,当且仅当 26 个小写字母 ‘a’∼‘z’都是好字符。
现在想知道字符串 s 是否为好字符串。
输入描述:
第一行输入一个整数 n (1≦n≦100),表示字符串 s 的长度。 
第二行输入一个长度为 n 的字符串 s,仅由大小写字母组成。
输出描述:
如果字符串 s 为好字符串,输出 YES,否则输出 NO。注意输出均为大写字母。

解题思路:用两个数组进行统计一下,大写一组, 小写一组, 然后顺次匹配一下 

写完三题后,准备交了,第一题就wa了一次,应该是遍历去重后的a,遍历成原字符串s了

更简单直接的代码2的思路 

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n; cin>>n;
    string s; cin>>s;
    sort(s.begin(),s.end());
    int c=0;
    set<int> a(s.begin(),s.end());
//     cout<<a.size()<<endl;
    if(((int)a.size())&1) { cout<<"NO"; return 0; }
    unordered_map<char,int> mp; int cnt=0,cnt0=0;
    for(auto& x:a){
        if(x>='a'&&x<='z'&&mp.count((char)(x-32))){
            cnt++;
        }
        mp[x]++;
    }
//     cout<<cnt<<endl;
    int n0=a.size();
    if(cnt==n0/2) cout<<"YES";
    else cout<<"NO";
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n; cin>>n;
    string s; cin>>s;
    bool a[26]={false};
    bool b[26]={false};
    for (char ch:s) {
        if (ch>='a'&&ch<='z') {
            a[ch-'a']=true;
        } else { 
            b[ch-'A']=true;
        }
    }
    for (int i=0;i<26;i++) {
        if (a[i]!=b[i]) {
            cout<<"NO"<<endl;
            return 0;
        }
    }
    cout<<"YES"<<endl;
    return 0;
}

 B. 平均数

题目描述

班上有 n 名同学,其中每位同学都有一个数值,但是每位同学并不会告诉你这个数值为多少,他们只会告诉你这个数值是否大于 / 等于 / 小于这 n 个数值的平均数,具体地:
若 ai​=−1,表示第 i 名同学的数值小于平均数;
若 ai​=0,表示第 i 名同学的数值等于平均数;
若 ai=1,表示第 i 名同学的数值大于平均数。
其中平均数指的是这 n 个数值的平均数值(保留小数点,不四舍五入),如{3,4,5,6} 的平均数为 3+4+5+64=4.5。
但是,它们其中,有些人可能会说谎,请你检查并判断:若给定的这 n 个数 ai​ 满足平均数的情况,则输出 YES,否则输出 NO。

输入描述:

第一行输入一个整数 n (1≦n≦105),表示数组 a 的长度。 
第二行输入 n 个整数 a1,a2,…,an(−1≦ai​≦1),表示每一个同学的数字与平均数的关系。
输出描述:
如果给定的这 n 个数 ai​ 满足平均数的情况,则输出 YES,否则输出 NO。注意输出均为大写字母。

解题思路:题意就是一问一个人, 它回复你比平均数大, 还是比平均数小, 还是相等, 

只要总体回复中有一个1和-1都有就行, 特殊的是全为0, 输出YES

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n; cin>>n;
    vector<int> a(n); int num=0;
    for(int i=0;i<n;i++){
        cin>>a[i];
        num+=a[i];
    }
    if(num==0) { cout<<"YES"; return 0; }
    int cnt0=0,cnt1=0;
    for(int i=0;i<n;i++){
        if(a[i]>0) cnt0++;
        else if(a[i]<0) cnt1++;
    }
    if(cnt0>0&&cnt1>0) cout<<"YES";
    else cout<<"NO";
    return 0;
}

// avg=4

// -1 0 1 1

 C. 质数

题目描述
给你 q 次询问,每次询问给出两个整数 l,r,现在需要你将区间 [l,r][l,r][l,r] 内所有数分别放入两个集合 S1​,S2​ 其中之一,最终需要满足:
∙S1,S2​ 两个集合都至少有一个数,并且满足 gcd⁡(S1)=1 且 gcd⁡(S2)≠1。
现在,对于每次询问,在满足上述条件的情况下,求出 ∣len⁡(S1)−len⁡(S2)∣ 的最小值,如果没有满足的情况,则输出 −1。

注:若集合 S={3},则 gcd⁡(S)=gcd⁡(3)=3;若集合 S={6,9,12},则 gcd⁡(S)=gcd⁡(6,9,12)=3,其中 gcd 表示集合内所有数的最大公因数。

输入描述:
第一行输入一个整数 q (1≦q≦105),表示询问次数。 
此后 q 行,第 i 行输入两个整数 li,ri(1≦li​≦ri​≦1018),表示第 i 次询问的区间。
输出描述:
对于每次询问,新起一行输出一个整数,表示 ∣len⁡(S1)−len⁡(S2)∣ 的最小值,如果没有满足的情况,则输出 −1。

解题思路:两个集合, 集合S1中元素互质, 集合S2中元素不互质 

两个集合, 一个数不行的, 两个数, 一个是1,因为要连续, 所以另外一个数只能是2, 其他是不行的,  

统计区间中偶数和奇数的个数,如果只有一个奇数,eg: 2 3 4, 

当至少一个偶数和至少两个奇数, 奇数gcd为1,偶数gcd>1, 放到S1和S2中即可

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
    int q;
    cin >> q;
    while(q--){
        ll l, r;
        cin>>l>>r;
        ll n=r-l+1;
        if(n==1){
            cout<<-1<<endl;
            continue;
        }
        if(n == 2){
            if(l==1&&r==2){
                cout<<0<<endl;
            } else {
                cout<<-1<<endl;
            }
            continue;
        }
        ll z =(r/2)-((l-1)/2);
        ll e =n-z;
        if(e==1){
            cout<<1<<endl;
            continue;
        }
        if(z>=1&&e>=2){
            int d = abs(e-z);
            cout<<d<<endl;
            continue;
        }
        cout<<-1<<endl;
    }
    return 0;
}

 D . 众数

题目描述

给定一个长度为 n 的数组 a1,a2,…,an,现在你需要执行恰好一次如下操作:
,∙选择两个不同的位置 i,j (1≦i,j≦n; i≠j),ai变成的ai+1, aj变成 aj -1。
现在,我们想知道,对于每一种不同的操作方式后得到的新数组(不包含不操作的情况),它们的众数都会是什么。你需要将全部可能称为众数的数字去重后,从小到大依次输出。

【名词解释】
一个数组的众数:指的是这个数在数组中的出现次数最多,如果有多个数出现次数最多,则这些数中最大的那个数是众数,如:{1,2,2,4} 的众数为 2, {3,3,2,2,1,1} 的众数为 3。

输入描述:
第一行输入一个整数 n (2≦n≦103),表示数组的大小。 
第二行输入 n 个整数 a1,a2,…,an(1≦ai​≦10^6),表示数组的元素。
输出描述:
在一行上从小到大依次输出去重后的若干个整数,代表所有可能出现的众数。

解题思路:代码的时间复杂度是O(n^2 log n), 

用一个set维护当前数字的出现次数, 如果出现次数相同就按数值大小进行降序处理, 

然后对于每一组数据进行+1/-1的操作, 更新频率数组和相关的节点信息, 然后将当前众数添加到ans数组里面, 同时进行恢复操作

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int max_Num = 1e7 + 10;
struct Node{
    int num, cnt;
    bool operator<(const Node& other) const {
        if (cnt == other.cnt) {
            return num > other.num; 
        }
        return cnt > other.cnt; 
    }
};
set<Node> st;
vector<int> fq(max_Num);
void o2(int x, int d) {
    st.erase({x, fq[x]});
    fq[x] += d;
    st.insert({x, fq[x]});
}
void o1(int x, int d) {
    o2(x, -1);
    o2(x + d, 1);
}
set<int> ans;
int main() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        fq[a[i]]++;
    }
    for (int i = 0; i < max_Num; i++) {
        if (fq[i] != 0) {
            st.insert({i, fq[i]});
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) {
                continue;
            }
            o1(a[i], 1);
            o1(a[j], -1);
            ans.insert(st.begin()->num);
            o1(a[i] + 1, -1);
            o1(a[j] - 1, 1);
        }
    }
    for (auto& x : ans) {
        cout << x << " ";
    }
    cout << endl;
    return 0;
}

 E. 种类数

 题目描述

给定一个长度为 n 的数组 a1,a2,…,an​,定义一轮操作如下:
,∙令 x 为当前数组中所有数的种类数(即不同数的数量),随后对数组中的每一个元素都进行一次修改——对于每个索引 i (1≦i≦n),使得 ai ​ 变为 max⁡{0,ai−x}。
我们想知道,至少需要多少轮操作(可以为零轮),才能使得数组 a 中所有数变得相同。我们可以证明,有限次操作内一定可以达成目标。

输入描述:
第一行输入一个整数 n (1≦n≦105),表示数组的长度。 
第二行输入 n 个整数 a1,a2,…,an (0≦ai​≦10^18),表示数组的元素。
输出描述:
输出一个整数,代表要使得数组 a 中所有数变得相同的最少操作轮数。

解题思路:我赛时的代码时间复杂度是O(nlogn)但是就是超时过不了,

用二分, 我们每轮减的是某一个符合条件的区间而不是一个数字

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    int n;
    cin >> n;
    vector<ll> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
    bool f = false;
    for (ll x : a) {
        if (x == 0) {
            f = true;
            break;
        }
    }
    vector<ll> p;
    for (ll x : a) {
        if (x > 0) {
            p.push_back(x);
        }
    }
    if (p.empty()) {
        cout << 0 << endl;
        return 0;
    }
    ll ans = 0;
    ll d = 0;
    int st = 0;                            //指向数组中第一个未被完全减到 0 的数
    n = a.size();
    while (true) {
        int k = n - st + (f ? 1 : 0);
        if (k <= 1) {
            break;
        }
        ll m = a[st] - d;
        int x = k;
        ll t = (m + x - 1) / x;            //还需要几轮
        ans += t;
        d += x * t;
        int nxt = upper_bound(a.begin() + st, a.end(), d) - a.begin();
        if (nxt > st) {
            st = nxt;
            f = true;
        }
    }
    cout << ans << endl;
    return 0;
}

 F. 中位数

 

解题思路:贡献法, 枚举中位数, 求mid =1 -> n 的乘积, 每个mid ^(mid在所有肯呢个排列中的所有可能区间中位数的情况数),枚举所有可能的区间长度 len=1, len=2, len=3....len=n

len! * len*(n-len) ! * ( n-len +1)

比mid小:mid-1 比mid大:n-mid

mid左侧为 C (len/2).floor / mid-1 ; mid右侧为 C len-1-(len/2).floor / n-mid

然后从len=1 -> n累加

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int P=1610612741;
const int PM1=P-1;
int Qpow(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=res*a%P;
        a=a*a%P;
        b>>=1;
    }
    return res;
}
void solve(){
    int n;
    cin>>n;
    vector<vector<int>> C(n+1,vector<int>(n+1));
    for(int i=0;i<=n;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++){
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%PM1;
        }
    }
    vector<int> f(n+1);
    f[0]=1;
    for(int i=1;i<=n;i++){
        f[i]=1LL*f[i-1]*i%PM1;
    }
    //预处理
    vector<int> ff(n+1);
    for(int i=1;i<=n;i++){
        ff[i]=1LL*f[i]*f[n-1]%PM1;
        ff[i]=1LL*ff[i]*(n-i+1)%PM1;
    }
    int ans=1;
    for(int i=2;i<=n;i++){
        int tot=0;
        for(int l=1;l<=n;l++){
            int c=0;
            if(l%2==0){
                c=1LL*C[i-1][l/2]*C[n-i][l/2-1]%PM1;
            }else{
                c=1LL*C[i-1][l/2]*C[n-i][l/2]%PM1;

            }
            tot+=1LL*c*ff[l]%PM1;
        }
        ans=1LL*ans*Qpow(i,tot%PM1)%P;
    }
    cout<<ans<<endl;
}
signed main(){
    solve();
    return 0;
}

感谢大家的点赞和关注,你们的支持是我创作的动力! 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值