首页 > 其他分享 >Codeforces Round #811

Codeforces Round #811

时间:2022-09-22 23:12:32浏览次数:64  
标签:ch int Codeforces ++ le edgenum ans 811 Round

目录

写在前面

比赛地址:https://codeforces.com/contest/1714

没什么整理价值的题,但是 markdown 语法及博客文风复健。

A

\(t\) 组数据,每组数据给定一个睡觉时间,给定 \(n\) 个任务时间。时间均以 24 小时制的小时+分钟形式给出。
求到第一个任务时间的睡眠时间。
\(1\le t\le 100\),\(1\le n\le 10\)。
2S,256MB。

水。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
//=============================================================
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
	int t = read();
  while (t --) {
    int n = read(), H = read(), M = read();
    int Tim = 60 * H + M, ans = 10000;
    for (int i = 1; i <= n; ++ i) {
      int h = read(), m = read();
      int tim = 60 * h + m;
      if (tim >= Tim) ans = std::min(ans, tim - Tim);
      if (tim < Tim) ans = std::min(ans, 60 * 24 - Tim + tim);
    }
    printf("%d %d\n", ans / 60, ans % 60);
  }
	return 0;
}

B

\(t\) 组数据,每组数据给定一长度为 \(n\) 的数列 \(a\)。要求删去 \(a\) 的某个前缀,使 \(a\) 中不存在重复的数。
求删去的前缀最短的长度。
\(1\le t\le 10^4\),\(1\le n\le 2 \times 10^5\),\(1\le a_i\le n\),\(\sum n\le 2\times 10^5\)。
2S,256MB。

随便做。

\(a\) 的值域很小,开个桶倒序枚举 \(a_i\) 直至第一个重复元素即可。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
const int kN = 2e5 + 10;
//=============================================================
int a[kN];
bool val[kN];
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
	int t = read();
  while (t --) {
    int n = read(), ans = 0;
    for (int i = 1; i <= n; ++ i) a[i] = read();
    for (int i = n; i >= 1; -- i) {
      if (val[a[i]]) {
        ans = i;
        break;
      }
      val[a[i]] = true;
    }
    printf("%d\n", ans);
    for (int i = n; i >= ans; -- i) val[a[i]] = false;
  }
	return 0;
}

C

\(t\) 组数据,每组数据给定整数 \(s\),求最小的整数 \(x\),使得 \(x\) 的各位之和为 \(s\)。
\(1\le t\le 45\),\(1\le s\le 45\)。
1S,256MB。

爆搜,打表。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
//=============================================================
int ans[50] = {0,1,2,3,4,5,6,7,8,9,19,29,39,49,59,69,79,89,189,289,389,489,589,689,789,1789,2789,3789,4789,5789,6789,16789,26789,36789,46789,56789,156789,256789,356789,456789,1456789,2456789,3456789,13456789,23456789,123456789};
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
	int t = read();
  while (t --) {
    int n = read();
    printf("%d\n", ans[n]);
  }
	return 0;
}

D

\(q\) 组数据,每组数据给定字符串 \(t\) 和 \(n\) 个字符串 \(s_1\sim s_n\)。
当 \(s_i\) 为 \(t\) 的一个子串时,称 \(s_i\) 可以覆盖 \(t\) 该子串所在的区间。\(t\) 中的每个位置可以被多次覆盖,每个 \(s_i\) 可以被用来多次覆盖 \(t\)。
求使用所有 \(s_i\) 全部覆盖 \(t\) 所需的最少次数,并输出任意一种覆盖方案。
\(1\le q\le 100\),\(1\le |t|\le 100\),\(1\le n\le 10\),\(1\le |s|\le 10\)。
2S,256MB。

暴力,贪心。

数据范围这么小 KMP 都用不上。先暴力求子串,将子串抽象为若干线段,问题转化为给定一些数轴上的线段,求覆盖数轴最少的线段数量。

贪心地覆盖即可。将所有线段按照左端点升序,右端点降序排序,每次选出最长的、能够覆盖仍未被覆盖的位置的线段并使用即可。

//By:Luckyblock
/*
1
bababa
2
ba
aba
*/
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
const int kN = 2e4 + 10;
//=============================================================
int num, lent, lens, ans1, ans2[kN][2];
char t[kN], s[kN];
struct str {
  int w, l, r;
} a[kN];
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
bool CMP(str fir, str sec) {
  if (fir.l == sec.l) return fir.r > sec.r;
  return fir.l < sec.l;
}
void Work(int k_) {
  lens = strlen(s + 1);
  for (int j = 1; j + lens - 1 <= lent; ++ j) {
    bool flag = true;
    for (int k = j, l = 1; l <= lens; ++ k, ++ l) {
      if (t[k] != s[l]) {
        flag = false;
        break;
      }
    }
    if (flag) a[++ num] = (str) {k_, j, j + lens - 1};
  }
}
//=============================================================
int main() {
	int q = read();
  while (q --) {
    scanf("%s", t + 1);
    lent = strlen(t + 1);
    num = ans1 = 0;
    int n = read(), end = 1; 
    for (int i = 1; i <= n; ++ i) {
      scanf("%s", s + 1);
      Work(i);
    }
    std::sort(a + 1, a + num + 1, CMP);
    for (int i = 1; i <= num && end <= lent; ) {
      int far = 0, p = 0;
      for (; i <= num && a[i].l <= end; ++ i) {
        if (a[i].r > far) far = a[i].r, p = i;
      }
      if (far <= end - 1) break;
      end = far + 1, ++ ans1;
      ans2[ans1][0] = a[p].w, ans2[ans1][1] = a[p].l;
    }
    if (end > lent) {
      printf("%d\n", ans1);
      for (int i = 1; i <= ans1; ++ i) printf("%d %d\n", ans2[i][0], ans2[i][1]);
    } else {
      printf("-1\n");
    }
  }
	return 0;
}

E

\(t\) 组数据,每组数据给定一长度为 \(n\) 的数列 \(a\),给定一种操作。每次操作可以选定任意数列元素 \(a_i\),使 \(a_i+(a_i\bmod 10)\)。
求对数列进行任意次操作后,数列中各元素能否相等。
\(1\le t\le 10^4\),\(1\le n\le 2\times 10^5\),\(0\le a_i\le 10^9\),\(\sum n\le 2\times 10^5\)。
2S,256MB。

结论。

手玩一下:

\[\begin{align*} 1 + 1 = 2\\ \\ 2 + 2 = 4\\ 4 + 4 = 8\\ 8 + 8 = 16\\ 16 + 6 = 22\\ \\ 22 + 2 = 24\\ 24 + 4 = 28\\ 28 + 8 = 36\\ 36 + 6 = 42\\ \end{align*}\]

可以发现奇数进行操作后将变成偶数,偶数的操作以 4 次为一个周期,一个周期后该数将 \(+20\),特别的,个位数为 0 的数操作后不变,个位数为 5 的数进行一次操作后末尾将变成 0。

如果操作后所有数能够相等,则任意两个数经操作后可以相等,先考虑两个数的情况。如果两个数本就相等则跳过,再将两个数中的奇数一次操作后变为偶数,再经过若干次操作使两个数个位相等。可以发现,此时两数可以相等的充要条件是两数之差为 20 的倍数。

上述算法拓展至整个数列即可。将预先处理后的数列升序排序,从小到大处理即可。

注意特判个位为 0 的数。

//By:Luckyblock
/*
12 2
14 4
18 8
26 6

32 2
34 4
38 8
46 6

52 2

44 4
48 8
56 6
62 2

*/
#include <cstdio>
#include <cctype>
#include <algorithm>
const int kN = 2e5 + 10;
//=============================================================
int a[kN];
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
//=============================================================
int main() {
	int t = read();
  while (t --) {
    int n = read(), flag = true;
    for (int i = 1; i <= n; ++ i) a[i] = read();
    
    for (int i = 1; i <= n; ++ i) {
      if (a[i] % 2 == 1) a[i] += (a[i] % 10);
      while (a[i] % 10 != 2 && a[i] % 10 != 0) a[i] += (a[i] % 10);
    }

    std::sort(a + 1, a + n + 1);
    if (a[1] == a[n]) {
      printf("Yes\n");
      continue;
    }
    for (int i = 2; i <= n; ++ i) {
      if (a[i] == a[i - 1]) continue;
      if (((a[i] - a[i - 1]) % 20) || (a[i - 1] % 10 == 0)) {
        flag = false;
        break;
      }
    }

    printf("%s\n", flag ? "Yes" : "No");
  }
	return 0;
}

F

\(t\) 组数据,每组数据给定参数 \(n\)、\(d_{12}\)、\(d_{23}\)、\(d_{31}\),分别代表树的节点个数、节点 \(1\) 到 \(2\)、\(2\) 到 \(3\)、\(3\) 到 \(1\) 的距离,要求构造一棵树,满足上述要求。
求是否存在对应的构造方案,若存在则输出方案。
\(1\le t\le 10^4\),\(3\le n\le 2\times 10^5\),\(1\le d_{12},d_{23},d_{31}\le n - 1\)。
2S,256MB。

思路简单但是细节麻烦的构造。

首先构造出 \(1\) 到 \(2\) 的链,考虑 \(3\) 与该链的相对位置:

  1. 在 \(1\) 到 \(2\) 的链上某点上。
  2. 在 \(1\) 到 \(2\) 的链上某点向外引出的一条链上。
  3. 在 \(1\) 到 \(2\) 的链的延长线上。

发现仅有以上三种合法情况存在,则可根据上述情况的距离关系判断是否存在方案,然后大力讨论构造即可。具体参考代码。

//By:Luckyblock
/*
1
5 4 2 2

1
5 3 3 2

1
5 3 1 4

1
5 3 4 1

1
5 1 3 4

1
5 2 3 3

1
5 3 2 3

1
5 4 1 1
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
const int kN = 2e5 + 10;
//=============================================================
int n, d12, d23, d31, num;
int edgenum, ans[kN][2];
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
int abs(int x) {
  return x >= 0 ? x : -x;
}
bool Judge() {
  if (abs(d23 - d31) > d12) return false;
  if ((abs(d23 - d31) % 2) != (d12 % 2)) return false;

  if (abs(d23 - d31) == d12) {
    if (d23 > d31) return (n >= d23);
    else return (n >= d31);
  } else {
    if (d23 + d31 < d12) return false;
    return (n >= ((d12 + d31 + d23) / 2 + 1));
  }
}
void Work() {
  num = 3, edgenum = 0;

  if (d12 == 1) {
    ans[++ edgenum][0] = 1, ans[edgenum][1] = 2;
  } else {
    ans[++ edgenum][0] = 1, ans[edgenum][1] = ++ num;
    for (int i = 2; i < d12; ++ i) {
      ans[++ edgenum][0] = num, ans[edgenum][1] = ++ num;
    }
    ans[++ edgenum][0] = num, ans[edgenum][1] = 2;
  }

  if (abs(d23 - d31) == d12) {
    if (d23 > d31) {
      if (d31 > 1) {
        ans[++ edgenum][0] = 1, ans[edgenum][1] = ++ num;
        for (int i = d12 + 1; i < d23 - 1; ++ i) {
          ans[++ edgenum][0] = num;
          ans[edgenum][1] = ++ num;
        }
        ans[++ edgenum][0] = num, ans[edgenum][1] = 3;
      } else {
        ans[++ edgenum][0] = 1, ans[edgenum][1] = 3;
      }

      for (int i = num + 1; i <= n; ++ i) {
        ans[++ edgenum][0] = i, ans[edgenum][1] = 1;
      }
    } else {
      if (d23 > 1) {
        ans[++ edgenum][0] = 2, ans[edgenum][1] = ++ num;
        for (int i = d12 + 1; i < d31 - 1; ++ i) {
          ans[++ edgenum][0] = num;
          ans[edgenum][1] = ++ num;
        }
        ans[++ edgenum][0] = num, ans[edgenum][1] = 3;
      } else {
        ans[++ edgenum][0] = 2, ans[edgenum][1] = 3;
      }
      
      for (int i = num + 1; i <= n; ++ i) {
        ans[++ edgenum][0] = i, ans[edgenum][1] = 1;
      }
    }
  } else {
    int pos;
    if (d23 > d31) {
      pos = 4;
      for (int i = d12 - 2; i != abs(d23 - d31); i -= 2) ++ pos;
    } else {
      pos = num;
      for (int i = d12 - 2; i != abs(d23 - d31); i -= 2) -- pos;
    }

    if (d31 == pos - 2) {
      ans[++ edgenum][0] = pos, ans[edgenum][1] = 3;
    } else if (d31 == pos - 3) {
      ans[pos - 3][1] = 3, ans[pos - 2][0] = 3;
      for (int i = 1; i <= edgenum; ++ i) {
        if (ans[i][0] > pos) ans[i][0] --;
        if (ans[i][1] > pos) ans[i][1] --;
      }
      -- num;
    } else {
      ans[++ edgenum][0] = pos, ans[edgenum][1] = ++ num;
      for (int i = pos - 2; i < d31 - 1; ++ i) {
        ans[++ edgenum][0] = num;
        ans[edgenum][1] = ++ num;
      }
      ans[++ edgenum][0] = num, ans[edgenum][1] = 3;
    }
    
    for (int i = num + 1; i <= n; ++ i) {
      ans[++ edgenum][0] = i, ans[edgenum][1] = 1;
    }
  }
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  // freopen("2.txt", "w", stdout);
	int t = read();
  for (int i = 1; i <= t; ++ i) {
    n = read(), d12 = read(), d23 = read(), d31 = read();
    // printf("%d:", i);
    if (!Judge()) {
      printf("NO\n");
      continue;
    }
    printf("YES\n");
    Work();
    for (int i = 1; i < n; ++ i) printf("%d %d\n", ans[i][0], ans[i][1]);
  }
	return 0;
}

G

\(t\) 组数据,每组数据给定一棵 \(n\) 个节点的有根树,根节点为 \(1\)。第 \(i\) 条边有两个边权 \(a_i,b_i\)。定义一段路径的前缀为:从起点出发的,方向与该路径相同且长度不大于该路径的路径。
对于节点 \(2\sim n\),记从根节点到该节点的路径上边权 \(a_i\) 之和为 \(x\),求使得边权 \(b_i\) 之和不大于 \(x\) 的最长的路径前缀的长度。
\(1\le t\le 10^4\),\(2\le n\le 2\times 10^5\),\(1\le a_i,b_i\le 10^9\),\(\sum n \le 2\times 10^5\)。
3S,256MB。

dfs + 二分搜索。

dfs 过程中记录从根到该节点的路径上 \(b_i\) 的前缀和,二分即可。

//By:Luckyblock
/*
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
#define LL long long 
const int kN = 2e5 + 10;
//=============================================================
int n, ans[kN];
int edgenum, v[kN], ne[kN], a[kN], b[kN], head[kN];
LL sumb[kN];
//=============================================================
inline int read() {
	int f = 1, w = 0; char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1;
	for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0';
	return f * w;
}
void Add(int u_, int v_, int a_, int b_) {
  v[++ edgenum] = v_;
  a[edgenum] = a_;
  b[edgenum] = b_;
  ne[edgenum] = head[u_];
  head[u_] = edgenum;
}
int Query(int dep_, LL suma_) {
  int l = 1, r = dep_ - 1, ret = 0;
  for (; l <= r; ) {
    int mid = l + r >> 1;
    if (sumb[mid] <= suma_) {
      ret = mid;
      l = mid + 1;
    } else {
      r = mid - 1;
    }
  }
  return ret;
}
void Dfs(int u_, int dep_, LL suma_) {
  ans[u_] = Query(dep_, suma_);
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i], a_ = a[i], b_ = b[i];
    sumb[dep_] = sumb[dep_ - 1] + 1ll * b_;
    Dfs(v_, dep_ + 1, suma_ + 1ll * a_);
  }
}
void Init() {
  edgenum = 0;
  for (int i = 1; i < n; ++ i) ans[i] = head[i] = ne[i] = 0;
}
//=============================================================
int main() {
	int t = read();
  while (t --) {
    Init();
    n = read();
    for (int i = 2; i <= n; ++ i) {
      int u = read(), x = read(), y = read();
      Add(u, i, x, y);
    }
    Dfs(1, 1, 0);
    for (int i = 2; i <= n; ++ i) printf("%d ", ans[i]);
    printf("\n");
  }
	return 0;
}

写在最后

AK 一场傻逼 div3,耗时 5h+。

哈哈。

马达马达。

标签:ch,int,Codeforces,++,le,edgenum,ans,811,Round
From: https://www.cnblogs.com/luckyblock/p/16721154.html

相关文章

  • Pair of Topics CodeForces - 1324D
    PairofTopicsCodeForces-1324D你有两个长度为n的数列a和b。现在我们定义,若存在i和j,满足:(i<j)且(a[i]+a[j]>b[i]+b[j]),则我们称数对<i,j>为JNU数对你的目......
  • 【asp.net】background属性
    一、更改元素背景色可以为所有元素设置背景色,这包括body一直到em和a等行内元素。1、元素背景色p{background-color:gray;}2、背景色从元素中的文本向外延伸......
  • CodeTON Round 2 (Div. 1 + Div. 2) - E. Count Seconds
    思维+DP[Problem-E-Codeforces](https://codeforces.com/contest/1695/problem/D2)题意给一张有\(n\)个结点\(m\)条有向边的有向无环图,\(1<=n,m<=1000\),每......
  • Codeforces Round #298 (Div. 2) - D. Handshakes
    贪心+构造题意有\(n(1<=n<=2*10^5)\)个人,每分钟有一个人进入房间,房间里任意3个人可以组队开始工作并一直持续下去,且只要房间里至少有3个人,他们就可以在任意时间......
  • Codeforces Round #814
    难得遇上一把CF,结果unr了。AMainakandArray显然最优策略只有三种:选一个\(i\in[1,n-1]\)的\(a_i\)作为\(a_1\);选一个\(i\in[2,n]\)的\(a_i\)作为\(a......
  • CodeTON Round 1 D
    D.K-good我们考虑变式我们设我们有一个k(n-(k+1)k/2)%k=0n=(k+1)k/2+kp2n=k(k+1+2p)因为我们等式右边k和k+1+2p奇偶性不同我们要求的就是k而对于我们已知的就只......
  • Polycarp Writes a String from Memory CodeForces - 1702B
    PolycarpWritesaStringfromMemoryCodeForces-1702B给定大小为n的字符串,至多每3种不同的字母分为一组,最少将字符串分为多少组?Input第一行输入数据包含一个整......
  • Jzzhu and Children CodeForces - 450A
    JzzhuandChildrenCodeForces-450A有n个孩子在老师的学校上学。老师决定给这些孩子一些苹果。让我们将所有孩子编号为1到n。第i个孩子想要获得至少ai的苹果......
  • CodeForces-189A Cut Ribbon-必须装满的背包
    题意:给定n,s.t. a1*x1+a2*x2+a3*x3=n(1)max:x1+x2+x3对比完全背包,(1)式取等号而不是<=这个差别影响了我们的结果比如:n=7,a1=a2=5,a3=2如果按照完全背包的转移:则在dp[7......
  • Codeforces Round #813 (Div. 2) - D. Empty Graph
    构造Problem-D-Codeforces题意给\(n(1<=n<=10^5)\)个点,与权值\(a_i\),这\(n\)个点组成一个完全图,\(a_l\)与\(a_r\)连的边的权值为\(min(a_l,a_{l+1}...a_{r......