Contests 链接:Educational Codeforces Round 58
输出不在范围 [ l , r ] [l,r] [l,r] 内的最小的正整数 x x x,要求 x x x 是 d d d 的整数倍。
第一行为一个整数 q ( 1 ≤ q ≤ 500 ) q~(1\leq q\leq500) q (1≤q≤500),接下去有 q q q 行,第 i i i 行的三个整数分别为 l i , r i , d i ( 1 ≤ l i ≤ r i ≤ 1 0 9 , 1 ≤ d i ≤ 1 0 9 ) l_i,r_i,d_i~(1\leq l_i\leq r_i\leq10^9,1\leq d_i\leq10^9) li,ri,di (1≤li≤ri≤109,1≤di≤109)。
对于每一行询问,输出对应的答案。
输入 |
---|
5 2 4 2 5 10 4 3 10 1 1 2 3 4 6 5 |
输出 |
6 4 1 3 10 |
若 d d d 在 [ l , r ] [l,r] [l,r] 范围内,则输出 ( ⌊ r d ⌋ + 1 ) × d (\lfloor\frac{r}{d}\rfloor+1)\times d (⌊dr⌋+1)×d,否则输出 d d d。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
int T;
int l, r, x;
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &l, &r, &x);
if(x >= l && x <= r) {
printf("%d\n", r / x * x + x);
} else {
printf("%d\n", x);
}
}
return 0;
}
用一个字符串来表示一个手风琴,其必须要满足的格式为:由
[
开头,接着是一个:
,往后是连续的多个或零个|
,接着是一个:
和]
。给定一个字符串,问能否通过删除一些字符,使得最终剩下的字符串可以表示成一个手风琴,若能,求最长剩余字符串长度。
输入仅包含一个字符串 s ( 1 ≤ ∣ s ∣ ≤ 5 × 1 0 5 ) s~(1\leq|s|\leq5\times10^5) s (1≤∣s∣≤5×105),其中只包含小写字母以及
[
、]
、:
、|
这几种符号。
如果无法满足题意,则输出 − 1 -1 −1,否则输出能表示成手风琴的最长的字符串。
输入 |
---|
|[a:b:|] |
输出 |
4 |
输入 |
---|
|]:[|:] |
输出 |
-1 |
先找出最左边的
[
下标 l l l 以及最右边的]
的下标 r r r,要求 l < r l<r l<r,接着找在[l,r]
范围内最左边的:
以及最右边的:
,最后将这两个冒号间所有的|
个数统计出来,答案就是|
的个数 + 4 +4 +4。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const int maxn = 500000 + 100;
int len;
char str[maxn];
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
while(scanf("%s", str + 1) != EOF) {
len = strlen(str + 1);
int l = -1;
int r = -1;
for(int i = 1; i <= len; ++i) {
if(str[i] == '[') {
l = i;
break;
}
}
for(int i = len; i >= 1; --i) {
if(str[i] == ']') {
r = i;
break;
}
}
if(l == -1 || r == -1 || r <= l) {
printf("-1\n");
continue;
}
int ll = -1;
int rr = -1;
for(int i = l + 1; i < r; ++i) {
if(str[i] == ':') {
if(ll == -1) {
ll = i;
}
rr = i;
}
}
if(ll == -1 || rr == -1 || ll >= rr) {
printf("-1\n");
continue;
}
int ans = 4;
for(int i = ll + 1; i < rr; ++i) {
if(str[i] == '|') {
++ans;
}
}
printf("%d\n", ans);
}
return 0;
}
给定 n n n 条线段,第 i i i 条线段的两个端点分别为 [ l i , r i ] [l_i,r_i] [li,ri],将这 n n n 条线段分别放入两个非空集合中,要求从这两个集合中分别任意取一条线段出来,这两条线段没有任何公共部分。
第一行为一个整数 T ( 1 ≤ T ≤ 5 × 1 0 4 ) T~(1\leq T\leq5\times10^4) T (1≤T≤5×104),接下去有 T T T 组数据,每组数据第一行为一个整数 n ( 2 ≤ n ≤ 1 0 5 ) n~(2\leq n\leq10^5) n (2≤n≤105),数据保证所有数据的 n n n 的总和不超过 1 0 5 10^5 105,接下去 n n n 行每行两个整数 l i , r i ( 1 ≤ l i ≤ r i ≤ 2 × 1 0 5 ) l_i,r_i~(1\leq l_i\leq r_i\leq2\times10^5) li,ri (1≤li≤ri≤2×105)。
对于每组数据输出一行,若某组数据无解,则输出 − 1 -1 −1,否则输出 n n n 个整数 t 1 , t 2 , ⋯   , t n ( t i ∈ { 1 , 2 } ) t_1,t_2,\cdots,t_n~(t_i\in\{1,2\}) t1,t2,⋯,tn (ti∈{1,2}), t i = 1 t_i=1 ti=1 表示第 i i i 条线段被分到第 1 1 1 个集合中, t i = 2 t_i=2 ti=2 表示第 i i i 条线段被分到第 2 2 2 个集合中,若有多解则输出任意一个。
输入 |
---|
3 2 5 5 2 3 3 3 5 2 3 2 3 3 3 3 4 4 5 5 |
输出 |
2 1 -1 1 1 2 |
提示 |
在第一组数据中,两条线段应被放到不同的集合中,但答案并不一定必须是 2 1,也可以是 1 2。 在第二组数据中,第三条线段与前两条线段相交,因此它们应该被分在同一个集合中,这样另一个集合就会为空,不满足题意,因此答案为 − 1 -1 −1。 在第三组数据中,我们可以以任意方式将三条线段分配到两个不同的集合中,只要这两个集合非空就是合法的,因此总共有 6 6 6 种合法的答案。 |
将每条线段的两个端点拆开,左区间 l i l_i li 标为 + i +i +i,右区间 r i + 1 r_i+1 ri+1 标为 − i -i −i,以端点大小为主关键字从小到大、以下标为此关键词从小到大排序,最后对整个数组扫一遍,遇到左端点则放入集合中,遇到右端点则从集合中删除,最后用并查集维护相互覆盖的线段,只要存在至少两个连通块,就存在答案,将其中一个连通块中的线段放到集合 1 1 1 中,其他的连通块放入集合 2 2 2 中。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const int maxn = 100000 + 100;
struct Node {
int Index, x;
};
bool operator<(const Node &a, const Node &b) {
return a.x == b.x? a.Index < b.Index: a.x < b.x;
}
int T, n, l, r;
Node node[maxn << 1];
set<int> st;
int fa[maxn], ans[maxn];
void Init() {
for(int i = 1; i <= n; ++i) {
fa[i] = i;
}
}
int Find(int x) {
return x == fa[x]? x: fa[x] = Find(fa[x]);
}
void unit(int x, int y) {
int xx = Find(x);
int yy = Find(y);
fa[xx] = yy;
}
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
st.clear();
Init();
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &l, &r);
node[i].Index = i;
node[i].x = l;
node[i + n].Index = -i;
node[i + n].x = r + 1;
}
sort(node + 1, node + 1 + 2 * n);
for(int i = 1; i <= 2 * n; ) {
while(i <= 2 * n && node[i].Index < 0) {
st.erase(-node[i].Index);
++i;
}
if(i == 2 * n + 1) {
break;
}
int f;
if(st.empty()) {
f = node[i].Index;
} else {
f = *st.begin();
}
while(i <= 2 * n && node[i].Index > 0) {
st.insert(node[i].Index);
unit(node[i].Index, f);
++i;
}
}
bool flag = false;
int f = Find(1);
for(int i = 1; i <= n; ++i) {
if(Find(i) == f) {
ans[i] = 1;
} else {
flag = true;
ans[i] = 2;
}
}
if(!flag) {
printf("-1\n");
continue;
}
for(int i = 1; i <= n; ++i) {
if(i != 1) {
printf(" ");
}
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
给定一棵 n n n 个节点的树,树上的每个点都有一个权值 a i a_i ai,定义 g ( x , y ) g(x,y) g(x,y) 表示从节点 x x x 到节点 y y y 的路径上所有节点(包括 x , y x,y x,y 两点)权值的 gcd \gcd gcd,定义 d i s t ( x , y ) dist(x,y) dist(x,y) 表示从节点 x x x 到节点 y y y 的路径上所有节点的数量,对于任意一个节点有 d i s t ( x , x ) = 1 dist(x,x)=1 dist(x,x)=1。求在 g ( x , y ) > 1 g(x,y)>1 g(x,y)>1 的 x , y x,y x,y 对中, d i s t ( x , y ) dist(x,y) dist(x,y) 的最大值。
第一行为一个整数 n ( 1 ≤ n ≤ 2 × 1 0 5 ) n~(1\leq n\leq2\times10^5) n (1≤n≤2×105),第二行为 n n n 个整数 a 1 , a 2 , ⋯   , a n ( 1 ≤ a i ≤ 2 × 1 0 5 ) a_1,a_2,\cdots,a_n~(1\leq a_i\leq2\times10^5) a1,a2,⋯,an (1≤ai≤2×105),接下去 n − 1 n-1 n−1 行每行两个整数 x , y ( 1 ≤ x , y ≤ n , x ≠ y ) x,y~(1\leq x,y\leq n,x\neq y) x,y (1≤x,y≤n,x̸=y),表示节点 x x x 与节点 y y y 之间有一条连边,数据保证所有的边可以构成一棵树。
如果不存在满足条件的答案,输出 0 0 0,否则输出满足条件的 d i s t ( x , y ) dist(x,y) dist(x,y) 的最大值。
输入 |
---|
3 2 3 4 1 2 2 3 |
输出 |
1 |
输入 |
---|
3 2 3 4 1 3 2 3 |
输出 |
2 |
输入 |
---|
3 1 1 1 1 2 2 3 |
输出 |
0 |
定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以第 i i i 个节点为根,从其任意一个子节点往下的一条链,这条链上所有节点权值的 gcd \gcd gcd 为 j j j 的倍数的最长长度,则可以得到 d p dp dp 递推式:
d p [ i ] [ j ] = max ( d p [ s o n i ] [ j ] ) + 1 dp[i][j]=\max(dp[son_i][j])+1 dp[i][j]=max(dp[soni][j])+1其中 s o n i son_i soni 为节点 i i i 的所有子节点, j j j 为 i i i 的所有质因子,答案为:
a n s = max ( max ( d p [ s o n i ] [ j ] ) + n e x t _ m a x ( d p [ s o n i ] [ j ] ) + 1 ) ans=\max(\max(dp[son_i][j])+next\_max(dp[son_i][j])+1) ans=max(max(dp[soni][j])+next_max(dp[soni][j])+1)其中 n e x t _ m a x next\_max next_max 表示序列中的次大值。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const int maxn = 200000 + 100;
int n, ans, u, v;
int num[maxn];
vector<int> G[maxn];
vector<int> fac[maxn];
map<int, int> dp[maxn];
map<int, int>::iterator it;
int cnt;
int prime[maxn];
bool vis[maxn];
void Prime(int n) {
for(int i = 2; i <= n; ++i) {
if(!vis[i]) {
prime[cnt++] = i;
}
for(int j = 0; j < cnt && i <= n / prime[j]; ++j) {
int k = i * prime[j];
vis[k] = true;
if(i % prime[j] == 0) {
break;
}
}
}
}
void dfs(int f, int x) {
int len = G[x].size();
for(int i = 0; i < len; ++i) {
int pos = G[x][i];
if(pos == f) {
continue;
}
dfs(x, pos);
}
len = fac[num[x]].size();
for(int i = 0; i < len; ++i) {
int ffac = fac[num[x]][i];
int MMax = 0;
int Max = 0;
int llen = G[x].size();
for(int j = 0; j < llen; ++j) {
int pos = G[x][j];
if(pos == f) {
continue;
}
it = dp[pos].find(ffac);
if(it == dp[pos].end()) {
continue;
}
if(it->second >= Max) {
MMax = Max;
Max = it->second;
} else if(it->second > MMax) {
MMax = it->second;
}
}
ans = max(ans, 1 + Max + MMax);
dp[x][ffac] = 1 + Max;
}
}
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
Prime(maxn - 1);
for(int i = 0; i < cnt; ++i) {
for(int j = prime[i]; j < maxn; j += prime[i]) {
fac[j].push_back(prime[i]);
}
}
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
for(int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 1);
printf("%d\n", ans);
return 0;
}
给定两种操作:
- 从一个初始为空的集合中加入一张大小为 x × y x\times y x×y 的票据;
- 询问大小为 h × w h\times w h×w 的钱包是否能装下所有票据。
对于所有已经被加入集合的票据,满足以下任意一个条件,则钱包能够装下所有票据:
- x i ≤ h x_i\leq h xi≤h 且 y i ≤ w y_i\leq w yi≤w;
- x i ≤ w x_i\leq w xi≤w 且 y i ≤ h y_i\leq h yi≤h。
对于每次询问,输出钱包是否能够装下集合中所有的票据。
第一行包含一个整数 n ( 2 ≤ n ≤ 5 × 1 0 5 ) n~(2\leq n\leq5\times10^5) n (2≤n≤5×105),接下去有 n n n 次操作,每次操作格式为以下两个之一:
- + x y ( 1 ≤ x , y ≤ 1 0 9 ) +~x~y~(1\leq x,y\leq10^9) + x y (1≤x,y≤109),表示加入一张大小为 x × y x\times y x×y 的票据;
- ? h w ( 1 ≤ h , w ≤ 1 0 9 ) ?~h~w~(1\leq h,w\leq10^9) ? h w (1≤h,w≤109),询问大小为 h × w h\times w h×w 的钱包能否放下集合中的所有票据。
数据保证在第一个询问 2 2 2 之前至少存在一个询问 1 1 1,并且至少存在一个询问 2 2 2。
对于每次询问,输出 Y E S YES YES 或 N O NO NO,表示答案。
输入 |
---|
9 + 3 2 + 2 3 ? 1 20 ? 3 3 ? 2 3 + 1 5 ? 10 10 ? 1 5 + 1 1 |
输出 |
NO YES YES YES NO |
对于每次放入的票据,每次取短边的最大值和长边的最大值,对于每次询问,只要短边的最大值小于等于钱包的短边,长边的最大值小于等于钱包的长边即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
int n, l, r, maxl, maxr;
char ch[2];
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
while(scanf("%d", &n) != EOF) {
maxl = 0;
maxr = 0;
for(int i = 0; i < n; ++i) {
scanf("%s%d%d", ch, &l, &r);
if(l > r) {
swap(l, r);
}
if(ch[0] == '+') {
maxl = max(maxl, l);
maxr = max(maxr, r);
} else {
if(l >= maxl && r >= maxr) {
printf("YES\n");
} else {
printf("NO\n");
}
}
}
}
return 0;
}