4.28~5.4
蓝桥杯15届国赛B
题目可以在官网https://www.lanqiao.cn/上查到
填空A
暴力找每个长度为8~16的子区间,然后判断是否满足条件即可
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
string s = " kfdhtshmrw4nxg#f44ehlbn33ccto#mwfn2waebry#3qd1ubwyhcyuavuajb#vyecsycuzsmwp31ipzah#catatja3kaqbcss2th";
int si = s.size()-1, sum = 0;
for(int i=1;i<=si;i++){
bool num = 0, fu = 0;
for(int j=i;j<=i+15 && j<=si;j++){
if(s[j] - '0' >= 0 && s[j] - '0' <= 9) num = 1;
else if(s[j] == '#')fu = 1;
if(j >= i+7 && num && fu) sum++;
}
}
cout << sum << '\n';
return 0;
}
填空B
数学题,用数学方法做
可以发现,分母是一样的,令分子为分别s1,s2,s3,可以算出,a🅱️c = s1s3 : s1s2 : s2*s3,令d为abc比值的最大公约数,求出满足a🅱️c的最小整数
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int s1 = 2585, s2 = 2632, s3 = 1540;
int d = __gcd(s1*s3,__gcd(s1*s2,s2*s3));
cout << s1*s3/d << ',' << s1*s2/d << ',' << s2*s3/d << '\n';
return 0;
}
C
题目数据量大,有一个5e7的方法可以过:
枚举每一条线段上的整数点,用哈希表来存点,如果这个点的统计次数>=2,那么就表示可以设为会议地点
怎么枚举每一条线段的整数点呢?
当这条线段平行于坐标轴时,x轴增量就是(x2 > x1) - (x1 > x2),y轴增量就是(y2 > y1) - (y1 > y2)
否则,x轴增量就是(x2-x1)/g,其中g是Δx和Δy的最大公约数;y轴增量同理
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
map <int,int> hash_[maxn];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n, ans = 0;
cin >> n;
while(n--){
int x1,x2,y1,y2;
cin >> x1 >> y1 >> x2 >> y2;
int dex = abs(x2-x1), dey = abs(y2-y1);
int g = __gcd(dex,dey);
if(x1 == x2 || y1 == y2){
int stx = (x2 > x1) - (x1 > x2), sty = (y2 > y1) - (y1 > y2);
while(x1 != x2 || y1 != y2){
hash_[x1][y1]++;
if(hash_[x1][y1] == 2) ans++;
x1 += stx;
y1 += sty;
}
if(++hash_[x2][y2] == 2) ans++;
}
else{
int stx = (x2-x1)/g, sty = (y2-y1)/g;
while(x1 != x2 || y1 != y2){
hash_[x1][y1]++;
if(hash_[x1][y1] == 2) ans++;
x1 += stx;
y1 += sty;
}
if(++hash_[x2][y2] == 2) ans++;
}
}
cout << ans << '\n';
return 0;
}
D
二分找最小的最长距离L
每个点之间增加的点的数量是ceil(dis/L)-1,dis是相邻两点间的距离
使用技能可以看成是多了一个增加点,也就是增加的点的总数变为m+1
对于每一个二分找的L,用检查函数来检查增加点的总数cnt是否小于等于m+1
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int a[maxn], n, m;
bool check(int L){
int cnt = 0;
for(int i=1;i<=n;i++){
cnt += ceil((1.0*a[i] - 1.0*a[i-1]) / L) - 1;
//cout << "L: " << L << " jia: " << ceil((1.0*a[i] - 1.0*a[i-1]) / L) - 1 << '\n';
}
return cnt <= m+1;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
a[0] = 0;
int l = 1, r = a[n];
while(l < r){
int mid = (l+r) >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << '\n';
return 0;
}
E
贪心+排序
这道看似简单的题我交了6发......,只能说坑多
首先,字典序最小就是一个坑,要使得字典序最小,那么对于s2的第i个字符,要在s1里找到第一个ASCⅡ码严格大于它的字符,也就是说在s2和s1的某个字符相等的情况下,要优先输出s1的字符
然后注意边界问题
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m;
string s1,s2;
cin >> n >> m >> s1 >> s2;
int p1 = 0, p2 = 0;
sort(s2.begin(),s2.end());
while(p1<=n || p2<=m){
if(p1 == n && p2 == m) break;
if(p1 == n) cout << s2[p2++];
else if(p2 == m) cout << s1[p1++];
else if(s1[p1] > s2[p2]) cout << s2[p2++];
else cout << s1[p1++];
}
cout << '\n';
return 0;
}
F
题目标签是DP,题解也是清一色的dp解法,没有其他解法的题解,BUT ! 这道题明显贪心更简单呐?题解里居然还有人说贪心难写 bug多,NO!按我这么贪 一遍就过
准备两个数组 a 和 ra ,a存输入的原始数据,ra存原始数据的二进制反转数据
再准备一个数组存每个ra[i] > a[i]的区间,这里我用vector来存
贪心思想,存完vector数组后降序排序,取前min(m,vec.size())个数据就可以算出最大的增加值,这个增加值加上原来的总和就是答案了
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e3+5;
int a[maxn],ra[maxn],n,m;
struct node{
int add,l,r;
};
vector <node> vec;
bool cpa(node a,node b){
return a.add > b.add;
}
void rev(int a,int i){
queue <int> q;
while(a){
int yu = a%2;
a /= 2;
q.push(yu);
}
int num = 0;
while(!q.empty()){
num += q.front() * pow(2,q.size()-1);
q.pop();
}
ra[i] = num;
return;
}
int f(int index){
int sum = 0;
for(int i=index;i<=n;i++){
if(ra[i] <= a[i]){
vec.push_back({sum,index,i-1});
return i-1;
}
sum += ra[i] - a[i];
}
vec.push_back({sum,index,n});
return n;
}
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
int sum = 0;
for(int i=1;i<=n;i++){
cin >> a[i];
sum += a[i];
rev(a[i],i);
}
for(int i=1;i<=n;i++){
if(ra[i] > a[i]){
i = f(i);
}
}
sort(vec.begin(),vec.end(),cpa);
int si = vec.size();
for(int i=0;i<si && i<m;i++){
sum += vec[i].add;
}
cout << sum << '\n';
return 0;
}
牛客月赛114
题目链接:https://ac.nowcoder.com/acm/contest/106859

哪个杀批出的题,我这就去给三国杀刷好评,定叫你好评如潮
A
签到
#include <bits/stdc++.h>
using namespace std;
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
for(int i=1;i<=n;i++){
int a;
cin >> a;
if(i == 1) cout << (a>1? (a+1<=5 ? a+1:5):2) << ' ';
else cout << (a>1? (a-1<=5 ? a-1:5):0) << ' ';
}
cout << '\n';
return 0;
}
B
这场赛居然有两道签到题...看来后面的题比较难了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
bool vis[maxn];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin >> n;
for(int i=0;i<n;i++){
int cache;
cin >> cache;
vis[cache] = 1;
}
long long sum = 0;
for(int i=1;i<=n;i++) if(vis[i]) sum += (long long)i;
cout << sum << '\n';
return 0;
}
C
大致题意就是给定一张图,让你找出这个图里有没有环
邻接表存图,然后bfs搜
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;
int n, x;
bool vis[maxn];
vector <int> e[maxn];
void bfs(){
queue <int> q;
q.push(x);
vis[x] = 1;
while(!q.empty()){
int start = q.front();
q.pop();
int si = e[start].size();
for(int i=0;i<si;i++){
if(vis[e[start][i]]){
cout << "Yes\n";
return;
}
q.push(e[start][i]);
vis[e[start][i]] = 1;
}
}
cout << "No\n";
return;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> x;
for(int i=1;i<=n;i++){
int f;
cin >> f;
e[f].push_back(i);
}
bfs();
return 0;
}
D
初看时考虑用dp,但是不好做。这种从队头队尾摸东西的题以前碰到过,比较常见的解法是做一个最大前后缀和,然后遍历一遍求最大和
总摸牌数是可以先计算出来的,记为t
遍历一遍,枚举前面拿x张,后面拿n-x张的最大值
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5+5;
int a[maxn],pre[maxn],hou[maxn];
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++) cin >> a[i];
int m = 0;
for(int i=1;i<=n;i++){
m += a[i];
pre[i] = max(pre[i-1],m);
}
m = 0;
for(int i=n;i>=1;i--){
m += a[i];
hou[i] = max(hou[i+1],m);
}
int t = 0;
for(int i=0;i<n;i++){
if(k<i) break;
k = k-i+1;
t++;
}
int ans = max(pre[t],hou[n-t+1]);
for(int i=1;i<t;i++) ans = max(ans,pre[i]+hou[n-(t-i)+1]);
cout << ans << '\n';
return 0;
}
剩下的题下周来,本周51真的玩爽了......

浙公网安备 33010602011771号