月赛的题目偏向思维,很有意思。
1.字符串
题目意思:给定一个字符串,判定好字符串的条件是,一个字母的大小写都在这个字符串里面。
思路:开两个数组,一个存放大写的某个字母是否出现,另一个存放小写的某个字母出现,最后用bool类型判断是否为1即可。
tips:这里说一下map<char>的写法,其实第一时间想到map也是对的,但是你会发现,没有出现的字母会难以判断,例如AbcCa中,B字母没有出现,如果写的简单的话,map容易漏判。写全的话,代码会偏复杂,量也会有点大。于是综合考虑情况下,用数组的条件是最好的。
#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<bool>a(26),b(26);
signed main(){int n;cin>>n;string ac;cin>>ac;/*for(auto c:ac){if(c>='a'&&c<='z')a[c-'a']=1;else b[c-'A']=1;}*/for(int i=0;i<n;i++){if(ac[i]>='a'&&ac[i]<='z')a[ac[i]-'a']=1;else b[ac[i]-'A']=1;}for(int i=0;i<26;i++){if(a[i]!=b[i]){cout<<"NO"<<endl;return 0;}}cout<<"YES"<<endl;
}
2.平均数
题目意思:给定n个数字,由0,-1,1构成,分别表示的是第i个数字等于平均数,小于平均数,大于平均数。判断是否有可能给定的这些n个数字满足平均数的情况....
思路:
不妨给出一些样例:
-1 0 1 1 1 1
-1 -1 -1 -1 1
观察上述两个案例,我们可以发现,-1和1分别表示的是小于和大于的情况,没有说明小于是具体小多少,大于具体大于多少。故,我们可以判断,若干个1一定可以被若干个-1抵消掉。到最后就是判断-1和1是否出现。
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){int n;cin>>n;bool flag1=0;bool flag2=0;for(int i=1,a;i<=n;i++){cin>>a;if(a==1)flag1=1;if(a==-1)flag2=1;}if(flag1==flag2)cout<<"YES"<<endl;else cout<<"NO"<<endl;
}
3.质数
题目意思:给定一个区间,将区间里面的数字分成两个集合,一个集合要求里面所有的数字的gcd是1,另一个集合要求所有的数字的gcd不为1,最后求两个集合大小之差的最小值。
思路:
给定一个区间,特判区间等于1的情况,随后分析大于等于2的情况。
我们拿出一个样例[3,7]进行分析,发现可以按照奇数和偶数进行分类。
[3,5,7]奇数的分成一类,[2,6]分成一类,观察后发现偶数分成一类的情况一定有gcd不等于1,奇数的情况由于都是邻近的奇数,gcd都是1。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int l,r;cin>>l>>r;if(l==r){cout<<-1<<endl;return;}if(l==1&&r==2){cout<<0<<endl;return ;}if(r-l+1==2){cout<<-1<<endl;//长度是2的情况下还有一个特殊的样例判断//当l=3 r=4的时候,gcd分别为3和4,不满足情况//只有当l=1 r=2这个特殊的情况下,才满足分组的条件return;}cout<<(r-l+1)%2<<endl;//判断l和r之间的长度的奇偶
}
signed main(){int n;cin>>n;while(n--)solve();
}
4.众数
题目意思:给定一组数字,可以任意选择两个数字,一个对数字进行+1,一个对数字进行-1,操作结束后找出新数组中的众数。如此往复求出所有众数,并从小到大进行输出。
思路:因为n的范围很小,只有3次方,所以我们可以直接进行暴力,开两层for,每一次对第一层的数字进行+1,第二层的数字进行-1,最后统计众数,并用bool进行标记。
统计众数我们可以通过set的pair<int,int>来进行存储,第一个int下放的是数量,第二个int下放的是数字。
#include <bits/stdc++.h>
using namespace std;
const int MAX_VALUE = 1e6 + 4;
void add(int x, vector<int>& sum, set<pair<int, int>>& s) {if (sum[x] > 0) {s.erase({sum[x], x});}sum[x]++;s.insert({sum[x], x});
}
void sub(int x, vector<int>& sum, set<pair<int, int>>& s) {s.erase({sum[x], x});sum[x]--;if (sum[x] > 0) {s.insert({sum[x], x});}
}
int main() {int n;cin >> n;vector<int> a(n + 1);vector<int> sum(MAX_VALUE, 0);vector<bool> vis(MAX_VALUE, false);set<pair<int, int>> s;for (int i = 1; i <= n; i++) {cin >> a[i];sum[a[i]]++;}for (int i = 0; i < MAX_VALUE; i++) {if (sum[i] > 0) {s.insert({sum[i], i});}}for (int i = 1; i <= n; i++) {// 尝试减少 a[i] 的值,增加a[i]+1的值sub(a[i], sum, s);add(a[i] + 1, sum, s);// 遍历数组中的每个其他元素for (int j = 1; j <= n; j++) {if (i == j) continue;// 尝试减少 a[j] 的值增加a[j]+1的值sub(a[j], sum, s);add(a[j] - 1, sum, s);// 标记当前最大频率的值vis[(*s.rbegin()).second] = true;//set默认是从小到大的排序// 恢复 a[j] 的值sub(a[j] - 1, sum, s);add(a[j], sum, s);}// 恢复 a[i] 的值sub(a[i] + 1, sum, s);add(a[i], sum, s);}for (int i = 0; i < MAX_VALUE; i++) {if (vis[i]) {cout << i << ' ';}}
}
5.种类数
题目意思:给定一个数组,每一轮对数组中的数字进行修改,可以对每一个数字减去整个数组的种类数,最低减为0,判断要经过多少轮之后数组中的数字才能全部变成同一个数。
思路:
题目说的是多少轮之后数组中的数字全部变成同一个,显然这同一个数只能是0。
假设一开始给定的n个数里面最坏的情况就是有n个种类数,那么这时只需要1次即可。
那么同理也存在要操作n次的情况。
于是这个题目可以拆解成模拟题目,先对数组进行unique操作,然后对剩余的数字进行从小到大的模拟操作。
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){int n;cin>>n;vector<int>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()); // 去除重复元素,得到唯一元素数组if(a.size()==1){ // 如果去重后只有一个元素,说明所有元素已经相同cout<<0<<endl;return 0;}int ans=0,sum=0,cnt=0; // ans记录操作轮数,sum记录累计减去的值,cnt用于标记是否处理过for(int i=0;i<a.size();i++){ // 遍历去重后的数组if(a[i]>sum){ // 如果当前元素减去累计减去的值小于等于0,跳过cnt=1;continue;}int m=a.size()-i+cnt; // 计算当前剩余的种类数a[i]-=sum; // 更新当前元素的值int d=(a[i]+m-1)/m; // 计算需要减去的轮数ans+=d; // 累加操作轮数sum+=d*m; // 更新累计减去的值cnt=1; // 标记已处理}cout<<ans<<endl; // 输出最少操作轮数
}