Dashboard - Codeforces Round 895 (Div. 3) - Codeforces
A
问多少次能使a 和 b相等,就是abs(a - b) / 2除c向上取整,也就是abs(a - b)除2c向上取整。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;void solve()
{int a, b, c;cin >> a >> b >> c;a = abs(a - b), c *= 2;cout << (a + c - 1) / c << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
B
真是一篇好阅读理解,读了好久
就是说陷阱会在踩到后经过s秒触发,触发后不能通过,最少往前走d + s / 2(向上取整)格子后就回不来了,把所有的d + s / 2比较取最小值然后减一就是答案。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;void solve()
{int n;cin >> n;int ans = 2e9;for(int i = 0; i < n; i ++){int a, b;cin >> a >> b;a = a + (b + 1) / 2;ans = min(ans, a);}cout << ans - 1 << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
C
如果是>2的偶数的话,x - 2和x就是一组解
如果l == r且l是奇数的话,可以求l的因子,设因子为d,x - d 和 d 都可以被d整除,这样也可以求出一组解
之后注意一些边界条件就好了。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;void solve()
{int l, r;cin >> l >> r;if(r < 4){cout << -1 << endl;return;}if(r % 2 && l == r){for(int i = 2; i * i <= l; i ++){if(l % i == 0){cout << l - i << ' ' << i << endl;return;}}cout << -1 << endl;return;}if(r % 2){cout << r - 3 << ' ' << 2 << endl;}else cout << r - 2 << ' ' << 2 << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
D
贪心。
设lcm为x和y的最大公倍数,lcm的倍数的位置有重合,先加后减等于零,在这里操作是没意义的。
加操作有意义的点的数量:n / x - n / lcm
减操作有意义的点的数量:n / y - n / lcm
加的话从n开始加,依次递减n-1、n-2这样
减的话从1开始加,依次递增2、3这样。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;void solve()
{ll n, x, y;cin >> n >> x >> y;ll gcd = __gcd(x, y);ll lcm = x * y / gcd;ll a = n / x - n / lcm, b = n / y - n / lcm;a = a * (2 * n - a + 1) / 2;b = b * (b + 1) / 2;cout << a - b << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
E
前缀和。
做出这道题需要了解的两个性质:
1. x ^ x = 0;
2. 0 ^ x = x;
根据这两条性质我们就可以求出任意一段连续区间的异或和,使用前缀数组实现,用b[]表示
b[n]表示从第一项异或到第n项
b[r] ^ b[l - 1]就等于 b[l - 1] ^ b[l] ^ ... ^ b[r] ^ b[l - 1] = b[l] ^ ... ^ b[r];
对于第一个操作,区间修改,如果一个数x的对应位置上的树为1,被修改后变成0,就相当于x没被启用,变成0了,就相当于异或x本身,
如果一个数x的对应位置上的树为0,被修改后变成1,就相当于x被启用了,变成了1,也相当于异或x本身。
先用一个ans计算出被启用的数的异或和,之后每进行一次区间修改就相当于异或一遍这个区间内的异或和,非常的easy。
然后第二个操作,如果是查1,直接输出ans就好了
如果是查2,输出前n项异或前缀和异或ans就好了
听说有人线段树过了,挺nb的,之后再学一学。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 100010;int a[N], b[N];void solve()
{int n;cin >> n;for(int i = 1; i <= n; i ++){cin >> a[i];b[i] = b[i - 1] ^ a[i]; }string s;cin >> s;s = ' ' + s;int ans = 0;for(int i = 1; i <= n; i ++){if(s[i] == '1'){ans ^= a[i];}}int Q;cin >> Q;while(Q --){int op;cin >> op;if(op == 1){int l, r;cin >> l >> r;int res = b[r] ^ b[l - 1];ans ^= res;}else{int x;cin >> x;if(x == 1)cout << ans << ' ';else cout << (b[n] ^ ans) << ' ';}}cout << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
赛后学的线段树做法:
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 100010;int n;
int a[N];
string s;
struct Node
{int l, r;int sum0, sum1;int f;
}tr[N * 4];void pushup(int u)
{tr[u].sum0 = tr[u << 1].sum0 ^ tr[u << 1 | 1].sum0;tr[u].sum1 = tr[u << 1].sum1 ^ tr[u << 1 | 1].sum1;
}void pushdown(int u)
{Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];if(tr[u].f){swap(left.sum0, left.sum1);swap(right.sum0, right.sum1);left.f ^= tr[u].f;right.f ^= tr[u].f;tr[u].f = 0;}
}void build(int u, int l, int r)
{if(l == r){if(s[l] == '0')tr[u] = {l, r, a[l], 0, 0};else tr[u] = {l, r, 0, a[l], 0};}else{tr[u] = {l, r, 0, 0, 0};int mid = l + r >> 1;build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);pushup(u);}
}void modify(int u, int l, int r)
{if(tr[u].l >= l && tr[u].r <= r){swap(tr[u].sum0, tr[u].sum1);tr[u].f ^= 1;}else{pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if(l <= mid)modify(u << 1, l, r);if(r > mid)modify(u << 1 | 1, l, r);pushup(u);}
}void solve()
{cin >> n;for(int i = 1; i <= n; i ++)cin >> a[i];cin >> s;s = ' ' + s;build(1, 1, n);int Q;cin >> Q;while(Q --){int op;cin >> op;if(op == 1){int l, r;cin >> l >> r;modify(1, l, r);}else{int x;cin >> x;if(x == 0)cout << tr[1].sum0 << ' ';else cout << tr[1].sum1 << ' ';}}cout << endl;
}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}
Node节点存两个值sum0和sum1,f作为懒标记。
F
i在要a[i]之前被卖出,其实就是拓扑排序,先输出没在环中的点,然后每个环中,值最小的那个点最后卖出一定是最优的,类似贪心。
其实我在想如果一个点同时出现在两个环中该怎么办,然后发现这种情况其实不存在
比如
如果一个点出现在多个环中,边数会比点数还多,因为又要求每个点的出度都为1,所以这种情况显然是与输入要求矛盾的,所以一个点一定最多出现在一个环内,证毕。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 100010;int n;
int h[N], e[N], ne[N], idx;
int d[N];
int a[N], b[N];
bool st[N];
vector<int> ans;
queue<int> q;void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}void bfs()
{while(q.size()){int t = q.front();q.pop();ans.push_back(t);for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];if(st[j])continue;d[j] --;if(!d[j]){q.push(j);st[j] = true;}}}
}void solve()
{idx = 0;ans.clear();cin >> n;priority_queue<PII, vector<PII>, greater<PII>> heap;for(int i = 1; i <= n; i ++)d[i] = 0;for(int i = 1; i <= n; i ++){st[i] = false;h[i] = -1;cin >> a[i];add(i, a[i]);d[a[i]] ++;}for(int i = 1; i <= n; i ++){cin >> b[i];heap.push({b[i], i});if(!d[i]){st[i] = true;q.push(i);}}bfs();while(ans.size() < n){int ver;while(heap.size()){PII t = heap.top();heap.pop();if(!st[t.second]){ver = t.second;break;}}st[ver] = true;for(int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if(st[j])continue;d[j] --;if(!d[j]){q.push(j);st[j] = true;}}bfs();ans.push_back(ver);}for(int i = 0; i < n; i ++)cout << ans[i] << ' ';cout << endl;}int main()
{IOSint _;cin >> _;while(_ --){solve();}return 0;
}