前言:
第三场比前面两场难度下降了很多,打起来还算比较舒服,这场理论上来说应该可以开7题了,但是场上只写了5题,有两题是思路但是需要再仔细考虑一下的,没开出来有点可惜。
D
思路:
签到题,范围挺小的,没多想,直接一发暴力。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; typedef long long int ll; int cal(int x){ int res = 0; while(x){ res += x % 10; x /= 10; } return res; } void solved(){ int n;cin >> n; int s = cal(n); for(int i = n + 1; 1 ;i++){ if(cal(i) == s){ cout << i << endl;return ; } } } int main(){ solved(); return 0; }
思路:
这题挺简单的,不知道为啥大家都被卡了,因为朋友直接需要相同的糖果,就说明朋友的朋友也是自己的朋友,那么我们只需要建一个图,然后dfs,每次dfs出一个联通块,找出里面的人数和朋友的最大需要的糖果数,把他们相乘然后加起来就行了。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long int ll; vector<int>G[maxn]; int a[maxn]; bool vis[maxn]; void dfs(int u,int &cnt,int &mm){ vis[u] = true; mm = max(mm,a[u]); cnt += 1; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(!vis[v]){ dfs(v,cnt,mm); } } } void solved(){ int n,m;scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++)scanf("%d",&a[i]); for(int i = 1; i <= m; i++){ int u,v;scanf("%d%d",&u,&v); G[u].push_back(v);G[v].push_back(u); } ll ans = 0; for(int i = 1; i <= n; i++){ if(!vis[i]){ int cnt = 0,mm = 0; dfs(i,cnt,mm); ans += mm * cnt; } } cout << ans << endl; } int main(){ solved(); return 0; }
I
思路:
很显然的一个dp,dp[i]:长度为i的从[1,i]的序列中,子序列的最大美观度。
那么我们面临的决策只有两个,那么当前字符与前面i个字符没有一个相同的即无法增加美观度,那么就是前面i个字符中有与当前i字符相同的这个时候可以增加1美丽度,在这两个决策中取max就行了。
dp[i] = max(dp[i - 1],dp[last[a[i]]] + 1)
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long int ll; int a[maxn]; int dp[maxn]; void solved(){ int n;cin >> n; for(int i = 1; i <= n; i++)cin >> a[i]; map<int,int>mp; dp[1] = 0;dp[2] = (a[1] == a[2]); mp[a[1]] = 1; mp[a[2]] = 2; for(int i = 3; i <= n; i++){ if(mp.count(a[i])) dp[i] = max(dp[i - 1],dp[mp[a[i]]] + 1); else dp[i] = dp[i - 1]; mp[a[i]] = i; } cout << dp[n] << endl; } int main(){ solved(); return 0; }
J
思路:
这是一个博弈题,emmmm,通过观察我们可以发现局面其实对牛妹更加有利,因为牛妹要的是偶数,那么如果最后场上有两张牌,即有三种可能,[奇数,偶数],[偶数,偶数],[奇数,奇数],那么奇数偶数偶数,偶数偶数偶数,奇数奇数偶数。也就是说只要场上只剩下两张牌,不管这些牌是什么,只要这个回合是牛妹的,牛妹必胜。
然后我们可以发现,如果最后场上只有两张牌,并且是牛牛的回合,奇数偶数奇数,奇数奇数奇数,偶数和偶数的永远是偶数,也就是说牛牛只有场上全是偶数才必败,否则必胜,然后我们可以发现如果场上的偶数牌数量<=1,牛牛必胜,否则牛牛必败(牛妹总有办法把局面变得都是偶数和牛牛)。
然后考虑一下n=1,2这题就做完了。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long int ll; int a[maxn]; void solved(){ int n;cin >> n; for(int i = 1; i <= n; i++)cin >> a[i]; if(n == 1){ if(a[1] & 1)cout << "NiuNiu" << endl; else cout << "NiuMei" << endl; return ; } if(n == 2){ if((a[1] % 2 == 1 && a[2] % 2 == 1) || (a[1] % 2 == 1 && a[2] % 2 == 0) || (a[1] % 2 == 0 && a[2] % 2 == 1)) cout << "NiuNiu" << endl; else cout << "NiuMei" << endl; } if(n & 1)cout << "NiuMei" << endl;//牛妹必胜 else { int f = 0; for(int i = 1; i <= n; i++){ if(a[i] % 2 == 0)f++; } if(f <= 1)cout << "NiuNiu" << endl; else cout << "NiuMei" << endl; } } int main(){ solved(); return 0; }
H
思路:
这题不难,就是细节比较多,他们的数字相同且字符串不同只有两种方法,要么把转为十进制的>10的且不为10的一个字符拆成两个字符输出,要么把两个字符组合成这个字符输出,要么不存在方案。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long int ll; char s[maxn]; void solved(){ scanf("%s",s + 1); int len = strlen(s + 1); string ans; string res; for(int i = 1; i <= len; i++){ int val = s[i] - 'a' + 1; if(val > 10 && val != 20){ int l = val / 10; int r = val % 10; ans += (char)(l + 'a' - 1); ans += (char)(r + 'a' - 1); cout << ans; for(++i;i <= len; i++)cout << s[i]; return ; }else ans += s[i]; if(val < 10)res += char(val + '0'); else { res += char((val / 10) + '0'); res += char((val % 10) + '0'); } } //cout << res << endl; string s; for(int i = 0; i < res.size() - 1; i++){ if(i + 2 < res.size() && res[i + 2] == '0')continue; if(i + 1 < res.size() && res[i] == '1' && res[i + 1] == '0'){ s += "j"; ++i; continue; } if(i + 1 < res.size() && res[i] == '2' && res[i + 1] == '0'){ s += "t"; ++i; continue; } int val = (res[i] - '0') * 10 + (res[i + 1] - '0'); if(val > 10 && val <= 26){ s += (char)(val + 'a' - 1); for(i = i + 2; i < res.size(); i++){ if(res[i] == '1' && res[i + 1] == '0')s += "j",++i; else if(res[i] == '2' && res[i + 1] == '0')s += "t",++i; else s += ((res[i] - '0') + 'a' - 1); } cout << s << endl; return ; } else { s += ((res[i] - '0') + 'a' - 1); } } cout << "-1" << endl; } int main(){ solved(); return 0; }
C
思路:
数据范围很小,直接暴力dfs,枚举k次攻击,每次攻击选择圆心在[-7,7],然后计算一下圆内切,外切,相交的数量即可。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; typedef long long int ll; struct circle{ int x,y,r; }c[maxn]; int n,k,r; int ans = 0; int px[maxn],py[maxn]; void dfs(int dep){ if(dep >= k){ int res = 0; for(int i = 1; i <= n; i++){ for(int j = 1; j <= dep; j++){ int dis = (px[j] - c[i].x) * (px[j] - c[i].x) + (py[j] - c[i].y) * (py[j] - c[i].y); if(dis <= 1ll * (r + c[i].r) * (r + c[i].r) || dis == (r - c[i].r) * (r - c[i].r)){ res ++;break; } } } ans = max(ans,res); return ; } for(int x = -7; x <= 7; x++){ for(int y = -7; y <= 7; y++){ px[dep + 1] = x;py[dep + 1] = y; dfs(dep + 1); } } } void solved(){ cin >> n >> k >> r; for(int i = 1; i <= n; i++){ scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].r); } dfs(0); cout << ans << endl; } int main(){ solved(); return 0; }
F
思路:
emmm,通过不断的wa和观察可以发现,只需要所以串的第一个#之前的字符串相同,和最后一个#的字符串相同即可,就输出-1,否则0.
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e6 + 10; typedef long long int ll; bool check(string a,string b){ int n = a.size(),m = b.size(); for(int i = 0; i < min(n,m); i++){ if(a[i] == '#' || b[i] == '#')break; if(a[i] != b[i])return true; } for(int i = n - 1,j = m - 1; i && j ; i--,j--){ if(a[i] == '#' || b[j] == '#')break; if(a[i] != b[j])return true; } return false; } void solved(){ int n;cin >> n; string a,b; bool f = true; for(int i = 1; i <= n; i++){ if(i == 1){ cin >> a;continue; }else{ b = a;cin >> a; } if(f && check(a,b)){ f = false; } } if(f)cout << "-1" << endl; else cout << "0" << endl; } int main(){ solved(); return 0; }
E
思路:
其实看这个题能***不离十的猜到,应该是用线段树来做,但是可能需要对题目对一定的转换才行。
所以,我们换一个角度思考,给定一个区间[l,r],如果这个区间的每个数的最近的第一个相同的数<=r就行,否则就不行。于是想暴力肯定是不行,那么我们可以用线段树维护每个数的下一个与这个数相同值的位置,那么可以用next[i]来表示,只需要从后往前for一遍,就可以求出来了,如果没有的话next[i]=n+1,然后用线段树维护这个next数组,那么考虑删除某个数,那么这个数的上一个位置会受到影响,因为上一个数的next就是当前这个数,当前这个数不在了,那么上一个数的next应该是当前这个数的next,那么我们还需要用一个数字来维护上一个数的位置,当发生修改时。
next[x] = n + 1
last[x] = 0
next[last[x]]=next[x]
last[next[x]]=last[x]
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 6e5 + 10; typedef long long int ll; int Next[maxn],last[maxn]; int a[maxn]; #define mid (l + r) / 2 #define lson (rt * 2) #define rson (rt * 2 + 1) int m[maxn << 2]; int tot; void build(int l,int r,int rt){ if(l == r){m[rt] = Next[++tot];return ;} build(l,mid,lson); build(mid + 1,r,rson); m[rt] = min(m[lson],m[rson]); } void update(int l,int r,int pos,int v,int rt){ if(l == r){m[rt] = v;return ;} if(pos <= mid)update(l,mid,pos,v,lson); else update(mid + 1,r,pos,v,rson); m[rt] = min(m[lson],m[rson]); } int query(int l,int r,int ql,int qr,int rt){ if(l >= ql && r <= qr){return m[rt];} int ans = 1e9; if(ql <= mid)ans = min(ans,query(l,mid,ql,qr,lson)); if(qr > mid)ans = min(ans,query(mid + 1,r,ql,qr,rson)); return ans; } void solved(){ int n,q;cin >> n >> q; for(int i = 1; i <= n; i++)cin >> a[i],Next[i] = n + 1,last[i] = 0; map<int,int>mp; for(int i = 1; i <= n; i++){ if(mp.count(a[i])) last[i] = mp[a[i]]; mp[a[i]] = i; } mp.clear(); for(int i = n; i >= 1; i--){ if(mp.count(a[i])) Next[i] = mp[a[i]]; mp[a[i]] = i; } //for(int i = 1; i <= n; i++)cout << Next[i] << ' ';cout << endl; build(1,n,1); while(q--){ int ins;scanf("%d",&ins); if(ins == 1){ int x;scanf("%d",&x); if(last[x] != 0) update(1,n,last[x],Next[x],1); update(1,n,x,n + 1,1); Next[last[x]] = Next[x]; last[Next[x]] = last[x]; Next[x] = n + 1; last[x] = 0; }else{ int l,r;scanf("%d%d",&l,&r); printf("%d\n",query(1,n,l,r,1) <= r); } } } int main(){ solved(); return 0; }