听了B站冬权九暮大佬的讲解,E题思如泉涌,自己顺着思路做下来了
思路:定1求1,将所有能打到国王的棋子位置求出,看是否能打到王后。
// Problem: A. Forked!
// Contest: Codeforces - Codeforces Round 914 (Div. 2)
// URL: https://codeforces.com/contest/1904/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
priority_queue, greater >mi;//小根堆
priority_queue ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vectora(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
int tx[4] = {-1 , -1 , 1 , 1};
int ty[4] = {1 , -1 , 1 , -1};
void solve()
{
int a , b;
cin >> a >> b;
map , int>pl;
int x1 , y1 , x2 , y2;
cin >> x1 >> y1 >> x2 >> y2;
int cnt = 0;
for(int i = 0 ; i < 4 ; i ++){
int nx = x1 + tx[i] * a;
int ny = y1 + ty[i] * b;
if((abs(x2 - nx) == a && abs(y2 - ny) == b) ||( abs(x2 - nx) == b && abs(y2 - ny) == a)){
if(!pl.count({nx,ny})){
cnt++;
pl[{nx,ny}] = 1;
}
}
}
for(int i = 0 ; i < 4 ; i ++){
int nx = x1 + tx[i] * b;
int ny = y1 + ty[i] * a;
if((abs(x2 - nx) == a && abs(y2 - ny) == b) ||( abs(x2 - nx) == b && abs(y2 - ny) == a)){
if(!pl.count({nx,ny})){
cnt++;
pl[{nx,ny}] = 1;
}
}
}
cout << cnt << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
思路: 假如只考虑对一个操作,那么可以想到对a数组先进行一个排序,然后从小到大逐个删除元素,直到没法删除为止,这样是最优情况。接下来考虑如何对所有操作:可以发现元素越大,最后所能移除的元素数量也是越大的,而且属于包含关系,因此可以从小到大的处理a中元素,并且由于是包含关系,所有元素公用一个分数即可。
// Problem: B. Collecting Game
// Contest: Codeforces - Codeforces Round 914 (Div. 2)
// URL: https://codeforces.com/contest/1904/problem/B
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pairpl;
priority_queue, greater >mi;//小根堆
priority_queue ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vectora(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
cin >> n;
vectorans(n , 0);
vectorpos(n , 0);
for(int i = 0 ; i < n ; i ++){
pos[i] = i;
}
for(int i = 0 ; i < n ; i ++)
cin >> a[i];
auto cmp = [&](LL x , LL y){
return a[x] < a[y];
};
sort(pos.begin() , pos.end() , cmp);
LL sum = 0;
int l = 0;
for(int i = 0 ; i < n ; i ++){
if(l == i){
sum += a[pos[l]];
l ++;
}
while(l < n && sum >= a[pos[l]]){
sum += a[pos[l]];
l++;
}
ans[pos[i]] = l - 1;
}
for(int i = 0 ; i < n ; i ++){
cout << ans[i] << " ";
}
cout << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
思路:可以发现,当操作数大于等于3时,一定能构造出0。第一步 c = a - b , 第二步 d = a - c , 第三步 e = d - b = a - c - b= a - a - b - b = 0。 当操作数为1时,最小值必定存在于原数组以及所有能构造出的数当中。当操作数为2时,观察数据发现可以暴力枚举,直接暴力枚举出所有可能构造出的数,然后模拟构造出的数在第二轮的情况。在第二轮的情况中,当前所构造出的数不需要与其他所有的数都操作,只需要与最接近它的两个数相操作即可。
// Problem: C. Array Game
// Contest: Codeforces - Codeforces Round 914 (Div. 2)
// URL: https://codeforces.com/contest/1904/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
#define int long long
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pairpl;
priority_queue, greater >mi;//小根堆
priority_queue ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vectora(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
cin >> n >> m;
for(int i = 0 ; i < n ; i ++)
cin >> a[i];
if(m >= 3){
cout << 0 << endl;
}
else{
sort(a.begin() , a.begin() + n);
int maxx = 1e18 + 10;
for(int i = 0 ; i < n ; i ++){
maxx = min(maxx , a[i]);
}
if(m == 1){
for(int i = 0 ; i < n - 1; i ++){
maxx = min(maxx , a[i + 1] - a[i]);
}
cout << maxx << endl;
}
else{
for(int i = 0 ; i < n ; i ++){
for(int j = i + 1; j < n ; j ++){
int res = a[j] - a[i];
maxx = min(maxx , res);
auto it = upper_bound(a.begin() , a.begin() + n , res);
maxx = min(maxx , *it - res);
if(it != a.begin()){
it--;
maxx = min(maxx , res - *it);
}
}
}
cout << maxx << endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
思路:考虑不能的情况:
1、首先如果 , 那么将无法修改为
2、其次若要将修改为,需要找到数组a中等于的数。由于一次操作是取,所以如果从 当中存在比还要大的数,那么这个操作也是无法成立的。因此若想要操作成立,则需要尽可能的靠近,因此一次操作找出的为最接近的左右两个。
找出两个以后,还需要考虑能否满足 当中的所有数,若 当中的某个下标,那么在该次操作中会使得,那么将变为情况1。同样,若当中的某个下标 , 那么会使得,同样变为情况1。
接下来考虑怎么样的顺序去修改最好:可以发现若按照数组从小到大排序以后,先修改小的数,是不会影响后面的数的。若先修改大的数,可能会使得前面小的数变为情况1。
整个题目变成了求数组中等于某个数的位置和若干区间内最大的数和最小的数。前者用set二分查找很方便,后者用ST表解决比较方便。
// Problem: D1. Set To Max (Easy Version)
// Contest: Codeforces - Codeforces Round 914 (Div. 2)
// URL: https://codeforces.com/contest/1904/problem/D1
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pairpl;
priority_queue, greater >mi;//小根堆
priority_queue ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
int a[N];
int b[N];
int Max[N][21];
int Min[N][21];
struct ST{//RMQ问题
void init(){
for(int i = 1 ; i <= n ; i ++){
Max[i][0] = a[i];
Min[i][0] = b[i];
}
}
void work(){
for(int j = 1;j <= 21;j++)
for(int i = 1;i + (1 << j) - 1 <= n ; i++){
Max[i][j] = max(Max[i][j - 1] , Max[i + (1 << (j - 1))][j - 1]);
Min[i][j] = min(Min[i][j - 1] , Min[i + (1 << (j - 1))][j - 1]);
}
}
int QueryMax(int l,int r)
{
int k = log2(r-l+1);
return max(Max[l][k],Max[r-(1<> n;
setpos[n + 5];
vector>v(n + 5);
ST st;
for(int i = 1 ; i <= n ; i ++)
cin >> a[i] , pos[a[i]].insert(i);
for(int i = 1 ; i <= n ; i ++)
cin >> b[i] ,v[i][0] = b[i] , v[i][1] = a[i] , v[i][2] = i;
sort(v.begin() + 1 , v.begin() + n + 1);
st.init();
st.work();
for(int i = 1 ;i <= n ; i++){
if(v[i][0] < v[i][1]){
cout <<"NO\n";
return;
}
else if(v[i][0] > v[i][1]){
int flag = 0;
int p = v[i][2];
auto pr = pos[v[i][0]].upper_bound(p);
if(pr != pos[v[i][0]].end()){
int r = *pr;
if(st.QueryMax(p ,r) == v[i][0] && st.QueryMin(p , r) == v[i][0]){
flag = 1;
}
}
if(flag == 0){
if(pr != pos[v[i][0]].begin()){
pr--;
int l = *pr;
if(st.QueryMax(l , p) == v[i][0] && st.QueryMin(l , p) == v[i][0]){
flag = 1;
}
}
}
if(!flag){
cout <<"NO\n";
return;
}
}
}
cout <<"YES\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
思路:同赛后题解一样,就是题解代码有点看不懂,就自己写了一版。
// Problem: E. Tree Queries
// Contest: Codeforces - Codeforces Round 914 (Div. 2)
// URL: https://codeforces.com/contest/1904/problem/E
// Memory Limit: 512 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pairpl;
priority_queue, greater >mi;//小根堆
priority_queue ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vectora(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
struct HLD {//轻重链剖分
int n;
std::vector siz, top, dep, parent, in, out, seq;//子树大小 所在重链的顶部节点 深度 父亲 子树DFS序的起点 子树DFS序的终点
std::vector> adj;
int cur = 1;
HLD() {}
HLD(int n) {
init(n);
}
void init(int n) {
this->n = n;
siz.resize(n);
top.resize(n);
dep.resize(n);
parent.resize(n);
in.resize(n);
out.resize(n);
seq.resize(n);
cur = 0;
adj.assign(n, {});
}
void addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
void work(int root = 1) {
top[root] = root;
dep[root] = 0;
parent[root] = -1;
dfs1(root);
dfs2(root);
}
void dfs1(int u) {
if (parent[u] != -1) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
}
siz[u] = 1;
for (auto &v : adj[u]) {
parent[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfs2(int u) {
in[u] = ++cur;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfs2(v);
}
out[u] = cur;
}
int lca(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) {
u = parent[top[u]];
} else {
v = parent[top[v]];
}
}
return dep[u] < dep[v] ? u : v;
}
int dist(int u, int v) {
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
int jump(int u, int k) {
if (dep[u] < k) {
return -1;
}
int d = dep[u] - k;
while (dep[top[u]] > d) {
u = parent[top[u]];
}
return seq[in[u] - dep[u] + d];
}
bool isAncester(int u, int v) {//是否为祖先
return in[u] <= in[v] && in[v] < out[u];
}
int rootedParent(int u, int v) {
std::swap(u, v);
if (u == v) {
return u;
}
if (!isAncester(u, v)) {
return parent[u];
}
auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
return in[x] < in[y];
}) - 1;
return *it;
}
int rootedSize(int u, int v) {
if (u == v) {
return n;
}
if (!isAncester(v, u)) {
return siz[v];
}
return n - siz[rootedParent(u, v)];
}
int rootedLca(int a, int b, int c) {
return lca(a, b) ^ lca(b, c) ^ lca(c, a);
}
}hld(N);
struct info{
LL Max;
friend info operator + (info a ,info b){
info c;
c.Max = max(a.Max , b.Max);
return c;
}
};
struct node{
int tag;
info val;
} seg[N * 4];
struct SegTree{
void update(int id)
{
seg[id].val = seg[id * 2].val + seg[id * 2 + 1].val;
}
void build(int id, int l, int r)
{
if (l == r) {
seg[id].val.Max = hld.dep[hld.seq[l]];
}
else{
int mid = (l + r) / 2;
build(id * 2, l, mid);
build(id * 2 + 1, mid + 1, r);
update(id);
}
}
void settag(int id, LL t)
{
seg[id].val.Max += t;
seg[id].tag += t;
}
void pushdown(int id, int l, int r)
{
if (seg[id].tag != 0){
int mid = (l + r) / 2;
settag(id * 2, seg[id].tag);
settag(id * 2 + 1, seg[id].tag);
seg[id].tag = 0;
}
}
void modify(int id, int l, int r, int ql, int qr, LL t)
{
if (l == ql && r == qr){
settag(id, t);
return;
}
if (ql > r || qr < l) // 区间无交集
return; // 剪枝
pushdown(id, l, r);
int mid = (l + r) / 2;
if (qr <= mid) modify(id * 2, l, mid, ql, qr, t);
else if (ql > mid) modify(id * 2 + 1, mid + 1, r, ql, qr, t);
else
{
modify(id * 2, l, mid, ql, mid, t);
modify(id * 2 + 1, mid + 1, r, mid + 1, qr, t);
}
update(id);
}
LL query(int id, int l, int r, int ql, int qr)
{
if (ql == l && qr == r) return seg[id].val.Max;
pushdown(id, l, r);
int mid = (l + r) / 2;
if (qr <= mid) return query(id * 2, l, mid, ql, qr);
else if (ql > mid) return query(id * 2 + 1, mid + 1, r, ql, qr);
else
{
return max(query(id * 2, l, mid, ql, mid) , query(id * 2 + 1, mid + 1, r, mid + 1, qr));
}
}
}Seg;
vector< vector< int > > que[N];
vectorans(N , 0);
void dfs(int u){
for(auto it : que[u]){
int len = it.size();
int id = it[0];
int l = hld.in[u] , r = hld.out[u];//子树范围
vector< pair >skip;
for(int i = 1 ; i < len ; i ++){
int x = it[i];
int ll = hld.in[x] , rr = hld.out[x];
if(ll < l && r <= rr ){
skip.pb({1 , hld.in[hld.parent[x]] - 1});
skip.pb({hld.out[hld.parent[x]] + 1 , n});
}
else{
skip.pb({ll , rr});
}
}
sort(skip.begin() , skip.end());
int prev = 1;
for(auto it : skip){
if(prev < it.x){
ans[id] = max(ans[id] , Seg.query(1 , 1 , n , prev , it.x - 1));
}
prev = max(prev , it.y + 1);
}
if(prev <= n)
ans[id] = max(ans[id] , Seg.query(1 , 1 , n , prev , n));
}
for(auto v : hld.adj[u]){
int l = hld.in[v] , r = hld.out[v];
Seg.modify(1 , 1 , n , l , r , -1);
Seg.modify(1 , 1 , n , 1 , l - 1 , 1);
Seg.modify(1 , 1 , n , r + 1 , n , 1);
int x = hld.parent[u];
hld.parent[u] = v;
dfs(v);
hld.parent[u] = x;
Seg.modify(1 , 1 , n , l , r , 1);
Seg.modify(1 , 1 , n , 1 , l - 1 , -1);
Seg.modify(1 , 1 , n , r + 1 , n , -1);
}
}
void solve()
{
cin >> n >> m;
hld.init(n + 5);
for(int i = 1 ; i < n ; i ++){
int u , v;
cin >> u >> v;
hld.addEdge(u , v);
}
hld.work();
Seg.build(1 , 1 , n);
for(int i = 1 ; i <= m ; i ++){
vectortmp;
int x , y;
cin >> x >> y;
tmp.pb(i);
for(int j = 0 ; j < y ; j ++){
int t;
cin >> t;
tmp.pb(t);
}
que[x].pb(tmp);
}
dfs(1);
for(int i = 1 ; i <= m ; i ++){
cout << ans[i] << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t = 1;
while(t--)
{
solve();
}
return 0;
}