https://codeforces.com/contest/2036
A:
思路:额,大家都会,没什么思路,直接见代码。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
void solve()
{
int n, m, k;
cin >> n;
vi a(n+1);
int flag = 0;
fo(i,1,n){
cin >> a[i];
}
for (int i=2; i<=n; i++){
int ma = max(a[i-1], a[i]);
int mi = min(a[i-1], a[i]);
if (!(ma - mi==5 || ma-mi==7)){
flag = 1;
break;
}
}
if (flag){
cout << "NO" << endl;
}
else{
cout << "YES" << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B:
思路:拿map存一下,再放在数组里排个序,取前n个加起来就行。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define endl '\n'
void solve()
{
int n, m, k;
cin >> n >> k;
map<int, int> mp;
for (int i = 1; i<=k; i++){
int x, y;
cin >> x >> y;
mp[x]+=y;
}
priority_queue<int> q;
for (auto [x, y] : mp){
q.push(y);
}
int sum = 0, cnt=0;
while (q.size() && cnt <n){
int y = q.top();
q.pop();
sum += y;
cnt++;
}
cout << sum << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C:
思路:先找一遍初始时得“1100”,再对替换得求替换前和替换后的值,做差加上初始值即可,想一下为什么判断时只要或一下就行,因为它最多只能满足一次,可以自己推一下。
#include <bits/stdc++.h>
using namespace std;
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
void solve()
{
int n, m, q;
string s;
cin >> s;
cin >> q;
int num = 0;
auto check = [&](int x)->bool
{
if (x < 0 || x + 3 >= s.size()) return false;
if (s[x]=='1'&&s[x+1]=='1'&&s[x+2]=='0'&&s[x+3]=='0') return true;
return false;
};
for (int i = 0; i + 3 < s.size(); i++) {
if (check(i)) {
num++;
}
}
while (q--) {
int i;
char v;
cin >> i >> v;
i--;
if (v != s[i]){
bool before = check(i-3)||check(i-2)||check(i-1)||check(i);
s[i] = v;
bool after = check(i-3)||check(i-2)||check(i-1)||check(i);
num += (after-before);
}
cout << (num>0? "YES" : "NO") << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D:
从外层向内层求,一层做一个数组记录然后遍历求“1543”的个数,注意最后的判断取%个数就比较好弄,这题还是比较典的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
void solve()
{
int n, m, k;
cin >> n >> m;
vector<string> s(n);
for (int i = 0; i<n; i++){
cin >> s[i];
}
vi arr(n*m);
int count = 0;
for (int i = 0; (i+1)*2<=n && (i+1)*2<=m; i++){
int pos = 0;
for (int j = i; j<m-i; j++) arr[pos++] = s[i][j];
for (int j = i+1; j<n-i-1; j++) arr[pos++] = s[j][m-i-1];
for (int j = m-i-1; j>=i; j--) arr[pos++] = s[n-i-1][j];
for (int j = n-i-2; j>i; j--) arr[pos++] = s[j][i];
for (int k = 0; k<pos; k++) {
if (arr[k]=='1'&&arr[(k+1)%pos]=='5'&&arr[(k+2)%pos]=='4'&&arr[(k+3)%pos]=='3') count++;
}
}
cout << count << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
E:
思路:有题可知,或运算后的下一层大于大于上一层,预先处理出数组,再根据要求进行二分,这是一道很好的二分题,需要对二分有清楚认识,正确区分左右边界,看代码很容易懂。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
void solve()
{
int n, m, k, q;
cin >> n >> k >> q;
vvi a(n+1, vi(k+1));
fo(i,1,n){
fo(j,1,k){
cin >> a[i][j];
a[i][j]|=a[i-1][j];
}
}
while (q--){
cin >> m;
int l_pos = 1, r_pos=n;
while (m--){
int i, c;
char o;
cin >> i >> o >> c;
if (o == '<'){
int l = 0, r = n+1;
while (l+1 < r){
int mid = (l+r) >> 1;
if (a[mid][i] < c) l = mid;
else r = mid;
}
if (l < r_pos) r_pos = l;
}
else {
int l = 0, r = n+1;
while (l+1 < r){
int mid = (l+r) >> 1;
if (a[mid][i] > c) r = mid;
else l = mid;
}
if (r > l_pos) l_pos = r;
}
}
if (l_pos <= r_pos) cout << l_pos << endl;
else cout << "-1" << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
F:
一道很好的异或题,让我对异或的理解也是加深和丰富了,建议去做做。
思路:首先要知道一个数异或自己为0,和异或前缀,下面是异或前缀的快速求法:
int get(int n) {
if (n % 4 == 0) {
return 0;
} else if (n % 4 == 1) {
return n - 1;
} else if (n % 4 == 2) {
return 1;
} else {
return n;
}
}
void solve() {
cin >> r; // 求r的前缀异或
r++;
int ans = get(r);
}
可以自己推几个数就明白了。
因此对于之间的数只要求出前缀,再把不用的去除掉,大概思路就是这样,接下看求区间
的异或,代码如下:
void solve()
{
int l, r, i, k;
cin >> l >> r >> i >> k;
int ans = get(++r)^get(l);
}
分清有趣为模不为
,无趣为模
为
,因此算出区间
的异或再异或掉无趣的,对无趣的数进行分析,以k为5为例画图:
前面部分又是连续区间,我们只要改变进制右移求前缀(这里注意向上取整),再左移回来
r = (r-k+(1<<i)-1) >> i;
l = (l-k+(1<<i)-1) >> i;
ans ^= (get(r)^get(l)) << i;
再考虑后半部分的个数,为偶数异或为0,为奇数异或还剩个k,最后异或一下。
全部代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int l, r, i, k;
cin >> l >> r >> i >> k;
auto get=[&](int n)->int
{
if (n % 4 == 0) return 0;
else if (n % 4 == 1) return n-1;
else if (n % 4 == 2) return 1;
else return n;
};
int ans = get(++r)^get(l);
r = (r-k+(1<<i)-1) >> i;
l = (l-k+(1<<i)-1) >> i;
ans ^= (get(r)^get(l)) << i;
if ((r ^ l) & 1){ //判断奇偶
ans ^= k;
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
小结:这场Div3还是考的是简单的知识的深度运用,比如二分,异或,但又不是简单,需要有深刻的认识,这场打昏了,希望下次能多开几道。
(算竞萌新,有误请指正)