Codeforces Round #679 (Div. 1, based on Technocup 2021 Elimination Round 1)

Codeforces Round #679 (Div. 1, based on Technocup 2021 Elimination Round 1)

T1 Perform Easily
mean
\(\quad\)给你6个数\(a_{1} a_{2} ... a_{6}\) ,再给你\(n\)个数\(b_{1} b_{2} ... b{n}\) ,问当所有\(b\)都减去任意一个\(a\)时,最大值减去最小值最小值是多少

idea
\(\quad\)我们考虑将所有的\(b_{i}\)都与任何一个\(a_{j}\)相减,那么就可以得到一个预处理好的结构,我们考虑这个结构具有两种属性

  • 相减之后的数值,我们简数值
  • 它是从哪一个\(b_{i}\)减过来的,我们简称位置

\(\quad\)现在这个问题就转化为了:我们要选择一些结构,使得所有记录的位置包含了所有的\(b_{i}\)并且数值的最大值减去最小值应该尽可能的小。
\(\quad\)我们可以考虑使用一个双指针来进行维护,先将、按数值从小到大排序,每一次选择一个恰好可以满足条件的位置,然后进行答案的更新,最后得到的最小答案就是本题的答案。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<climits>
#include<sstream>
using namespace std;

inline int read()
{
  char c ; int flag = 1;
  while((c = getchar()) < '0' || c > '9'){if(c == '-'){flag = -1;}}
  int count = c - '0';
  while((c = getchar()) >= '0' && c <= '9'){count *= 10 ; count += c - '0';}
  return count * flag;
}
inline void print(int x)
{
  if(x < 0){x = -x ; putchar('-');}
  if(x > 9){print(x / 10);}
  putchar(x % 10 + '0');
}

const int N = 1000100;
int a[7] , b[N];
struct Node{int x , b;}node[N];
bool cmp_Node(Node a , Node b){return a.x < b.x;}
int book[N];
int main()
{
  for(register int i = 1 ; i <= 6 ; i++){a[i] = read();}
  int n = read() ; int tot = 0;
  for(register int i = 1 ; i <= n ; i++){b[i] = read();}
  for(register int i = 1 ; i <= 6 ; i++)
  {
    for(register int j = 1 ; j <= n ; j++){tot++ ; node[tot] = (Node){b[j] - a[i] , j};}
  }
  sort(node + 1 , node + tot + 1 , cmp_Node);
  int l = 0 , r = 1 ; book[node[1].b] = 1 ; int cnt = 1;
  int ans = INT_MAX;
  while(1)
  {
    if(l == r && r == tot && cnt == n){ans = 0 ; break;}
    if(cnt != n && r == tot){break;}
    while(cnt != n && r < tot)
    {
      r++;
      if(book[node[r].b] == 0){cnt++;}
      book[node[r].b]++;
    }
    if(cnt != n && r == tot){break;}
    while(cnt == n && l <= r)
    {
      if(book[node[l].b] == 1){cnt--;}
      book[node[l].b]--;
      l++;
    }
    ans = min(ans , node[r].x - node[l - 1].x);
  }
  print(ans);
  return 0;
}

T2 Shurikens
mean
\(\quad\)觉得不太好简化,就大概说一下吧。给你一些操作,期中\(+\)表示放入了一些元素,\(-\)表示取出了所有元素当中最小的元素,现在告诉你有这么一些操作,请你判断它是否合理,如果不合理输出\(NO\),合理输出\(YES\),并且在下一行输出一个可能的放入元素大小,按放入顺序输出,开启了\(Special Judge\)

idea
\(\quad\)我们考虑使用一个栈来进行操作的维护,那么一些事后\(-\)\(+\)多的情况显然可以排除掉,对于剩下的情况,我们可以将每一个元素都抽象成一个节点,我们考虑在每一次有新元素入栈的时候从栈顶元素代表的节点向新进入栈的节点连一条边,每一次退出的事后向退出元素代表的节点附上元素的值,在所有操作结束之后就可以直接使用拓扑排序判断所有节点的后继是否都比本节点小,如果小为可行,如果大于了本节点就代表不可行(感性理解一下,可以画画图),为了方便我们可以定义一个无限大的超级节点0作为永远不变的栈低元素。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<ctime>
#include<cmath>
#include<climits>
#include<sstream>
using namespace std;
#include<stack>
#include<queue>

const int N = 1e5 + 10;
int head[N] , net[N] , vis[N] ; int tot;
inline void add(int u , int v){tot++ ; net[tot] = head[u] ; head[u] = tot ; vis[tot] = v;}
int a[N] ; int cnt = 0;
stack<int> s;
queue<int> q;
struct Node{int x , b;}node[N];
bool cmp_Node(Node a , Node b){return a.b < b.b;}

void tuop()
{
  q.push(0);
  while(!q.empty())
  {
    int u = q.front() ; q.pop();
    for(register int i = head[u] ; i ; i = net[i])
    {
      int v = vis[i];
      if(a[v] > a[u]){cout << "NO" ; exit(0);}
      q.push(v);
    }
  }
}

int main()
{
  ios::sync_with_stdio(false);
  int n;
  cin >> n;
  a[0] = INT_MAX;
  s.push(0);
  for(register int i = 1 ; i <= 2 * n ; i++)
  {
    char c;
    cin >> c;
    if(c == '+')
    {
      cnt++;
      add(s.top() , cnt);
      s.push(cnt);
    }
    else
    {
      int x;
      cin >> x;
      if(s.top() == 0){cout << "NO" ; return 0;}
      else{a[s.top()] = x ; node[s.top()] = (Node){x , s.top()} ; s.pop();}
    }
  }
  tuop();
  cout << "YES" << endl;
  sort(node + 1 , node + cnt + 1 , cmp_Node);
  for(register int i = 1 ; i <= n ; i++){cout << node[i].x << " ";}
  return 0;
}
原文地址:https://www.cnblogs.com/wanwanjiuhao7744/p/13886091.html