牛客小白月赛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;
}
感谢大家的点赞和关注,你们的支持是我创作的动力!