813A - The Contest
Pasha参加了一个有n道题的线上比赛。Pasha解决第i个问题需要 ai 秒的时间(毕竟是神犇,题题都能AC!)。任意一个时刻祂只能同时解决一个问题(结果只是个单线程),而且拥有超能力,能瞬间提交程序评测通过。不幸的是,这个比赛很多人参加,OJ老是瘫痪,Pasha发现OJ只在m秒内不是404(误,应该是50x),只会在j个时间片段 [lj,rj] 秒内正常运作。Pasha只能在不瘫痪的时候提交祂的程序。Pasha想知道祂最多能A几道题,我们需要告诉他最早在第几秒时他能提交所有的程序,或者他不能提交所有的程序。
输入
第一行只有1个正数
n(1 ≤ n ≤ 1000)
第二行n个正数
ai(1 ≤ ai ≤ 105)
,解决第i道题的时间
第三行一个正数
m(0 ≤ m ≤ 1000)
,OJ能运作的时间片段的个数。
接下来m行每行描述一个时间片段:
lj,rj(1 ≤ lj < rj ≤ 105)
,表示OJ开始正常工作和结束正常工作的时间$
保证这些时间片段没有交集,且按时间顺序给出。
输出
如果Pasha能AK,输出祂最早能AK的时间点。否则输出-1。
样例
样例输入1
2
3 4
2
1 4
7 9
样例输出1
7
样例输入2
1
5
1
1 4
样例输出2
-1
样例输入3
1
5
1
1 5
样例输出3
5
提示
第一个样例中,Pasha先AC第二道题,并立刻提交程序;然后在AC第一道题并在第7s时提交程序。
第二个样例中,Pasha不能在OJ正常工作的时候完成所有的题目。
第三个样例中,Pasha在第一个时间片段最后1s提交了所有的程序。
题解
题解什么的不存在,脸肿.jpg
代码
#include <cstdio>
#define FOR(i,j,k) for(i=j;i<=k;++i)
int main() {
int n, a, b, tot = 0, i;
scanf("%d", &n);
FOR(i,1,n) scanf("%d", &a), tot += a;
scanf("%d", &n);
FOR(i,1,n) {
scanf("%d%d", &a, &b);
if (a <= tot && tot <= b) {
printf("%d", tot);
goto end;
} else if (a > tot) {
printf("%d", a);
goto end;
}
}
puts("-1");
end:
return 0;
}
813B - The Golden Age
一个不幸运的年份
n
可以表示为
比如,如果
x=2,y=3
,第
4(=20+31)
和第
17(=23+32=24+30)
年就不是幸运的,而第18年就是幸运的。
而连续几年都幸运的年代就被称为黄金时代。
你的任务是写一个程序,找出最长的黄金年代,并且满足不早于第
l
年开始,不晚于第
输入
唯一的一行包含4个正数 x,y,l,r(2 ≤ x, y ≤ 1018,1 ≤ l ≤ r ≤ 1018)
输出
输出 [l,r] 内最长的黄金年代的长度。
样例
样例输入1
2 3 1 10
样例输出1
1
样例输入2
3 5 10 22
样例输出2
8
样例输入3
2 3 3 5
样例输出3
0
提示
第一个样例中,2,3,4,5,7,9,10是不幸运的,所以[1,1],[6,6],[8,8]是黄金年代。
第二个样例中的最长的黄金年代是[15,22]。
题解
容易知道 a,b≤64 ,所以 xa 和 yb 的个数就 ≤64∗64=4096 ,接下来就好做了,把所有不幸运的年份都算出来就好了。
代码
#include <iostream>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
using namespace std;
typedef long long ll;
const int N = 8192;
ll p[N], q[N], year[N];
int main() {
ll x, y, l, r, i, j, P, Q, Y = 0, ans = 0;
p[0] = q[0] = 1;
cin>>x>>y>>l>>r;
for (P = 0; p[P] <= r / x; ++P) p[P + 1] = p[P] * x; // 防止爆long long
for (Q = 0; q[Q] <= r / y; ++Q) q[Q + 1] = q[Q] * y;
FOR(i,0,P) FOR(j,0,Q) if (p[i] + q[j] <= r && p[i] + q[j] >= l) year[++Y] = p[i] + q[j];
year[++Y] = l - 1; year[++Y] = r + 1;
sort(year + 1, year + 1 + Y);
FOR(i,2,Y) ans = max(ans, year[i] - year[i - 1] - 1);
cout<<ans;
return 0;
}
813C - The Tag Game
Alice和Bob在一棵由n个节点组成的树(1为根节点)上玩一个游戏。Alice的棋子一开始在节点1,Bob的棋子一开始在节点 x(x ≠ 1) 。A和B轮流走,Bob先走。走一步的定义是将棋子保持不动或将棋子移到其相邻的点上(即两点间有边)。当Alice的棋子和Bob的棋子在同一个点上(A吃了B),游戏就结束了。Alice和Bob都很聪明,会做最好的选择(Alice希望最小化总步数而Bob希望最大化总步数)。请你写个程序算出游戏总步数。
输入格式
第一行2个正数n和x (
2 ≤ n ≤ 2⋅105
,
2 ≤ x ≤ n
).
接下来的
n − 1
行,每行2个正数
a
和
输出格式
输出游戏总步数(Alice走的步数和Bob走的步数的和)
样例
样例输入1
4 3
1 2
2 3
2 4
样例输出1
4
样例输入2
5 2
1 2
2 3
3 4
2 5
样例输出2
6
题解
一些显然的性质:
1. 无论Bob怎么走,Alice总是沿AB路径走而且不会某一步选择不动
2. Bob不会走回头路(这样做和在某个点停住不动是一个情况)
3. 可以认为Bob只在叶子停住不动(选择不动可以在中途也可以在最后,我们调整到最后)
4. AB间距不会增大(在2的前提下)
5. 一定是Alice最后走,Bob不会最后走(主动投入Alice温暖又邪恶的怀抱???)
因此我们可以想到这样的思路:首先1到x的路径离Alice 1近的路径上一半的点Bob一定到不了,剩下的点Bob不作死都可以到,那么Bob能到的这些点离1最远的就是答案的一半。
话说也就是那些Alice比Bob晚到的点中找,一个道理。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 200005, M = 2 * N;
#define FOR(i,j,k) for(i=j;i<=k;++i)
int n, x, h[N], p[M], v[M], vis[N], edge = 0;
int rec1[N], recx[N], path[N], len;
void add(int x, int y) {
p[++edge] = h[x]; v[edge] = y; h[x] = edge;
p[++edge] = h[y]; v[edge] = x; h[y] = edge;
}
bool dfs(int x, int fa, int dep) { // 先找AB路靠近Alice的那一半的点
path[dep] = x; len = dep;
if (x == 1) return true;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa && dfs(v[i], x, dep + 1))
return true;
return false;
}
void dfs2(int x, int fa, int dep, int *rec) {
rec[x] = dep;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa && !vis[v[i]])
dfs2(v[i], x, dep + 1, rec);
}
int main() {
int i, ans = 0, a, b;
scanf("%d%d", &n, &x);
FOR(i,1,n) rec1[i] = recx[i] = -1;
FOR(i,2,n) scanf("%d%d", &a, &b), add(a, b);
dfs(x, 0, 1); dfs2(1, 0, 1, rec1); // 算出Alice到各点的距离
FOR(i, len / 2 + 1, len) vis[path[i]] = 1; // 靠近Alice的一半的点Bob不可达
if (!vis[x]) dfs2(x, 0, 1, recx); // 剩下的可达
FOR(i,1,n) if (recx[i] != -1) ans = max(ans, rec1[i]); // Bob可达的点离Alice最远的就是答案
printf("%d", (ans - 1) * 2); // Bob 和 Alice 的距离的两倍
return 0;
}
813D - Two Melodies
有一个大序列,挑出2个不相交不为空的子序列,满足相邻两个元素差为1或模7相等。
写一个程序计算最大的满足条件的2个不相交子序列的长度和。
输入
第一行只有一个整数
n(2 ≤ n ≤ 5000)
,大序列元素个数.
第二行有n个整数
a1, a2, ..., an(1 ≤ ai ≤ 105)
大序列元素。
输出
输出符合条件的两个非空不相交子序列的长度和的最大值。
样例
样例输入1
4
1 2 4 5
样例输出1
4
样例输入2
6
62 22 60 61 48 49
样例输出2
5
提示
样例一的子序列为
[1,2],[4,5]
两个。
样例二的子序列为
[62,48,49],[60,61]
。如果先选
[62,61]
,第二个子序列的最大长度为2,不是最优。
题解
容易想到用
dp[i,j]
表示第一个子序列在第i个元素结束,第二个子序列在第j个元素结束。
而且也容易想到,如果a[k]和a[i]满足条件,那么dp[i,j]将用dp[k,j]更新答案,而且可以避免两个集合