CodeForces 813A|813B|813C|813D

来源:互联网 发布:阿里云服务器动态ip 编辑:程序博客网 时间:2024/06/06 18:54

813A - The Contest

Pasha参加了一个有n道题的线上比赛。Pasha解决第i个问题需要ai秒的时间(毕竟是神犇,题题都能AC!)。任意一个时刻祂只能同时解决一个问题(结果只是个单线程),而且拥有超能力,能瞬间提交程序评测通过。不幸的是,这个比赛很多人参加,OJ老是瘫痪,Pasha发现OJ只在m秒内不是404(误,应该是50x),只会在j个时间片段[lj,rj]秒内正常运作。Pasha只能在不瘫痪的时候提交祂的程序。Pasha想知道祂最多能A几道题,我们需要告诉他最早在第几秒时他能提交所有的程序,或者他不能提交所有的程序。

输入

第一行只有1个正数n(1n1000)
第二行n个正数ai(1ai105),解决第i道题的时间
第三行一个正数m(0m1000),OJ能运作的时间片段的个数。
接下来m行每行描述一个时间片段:lj,rj(1lj<rj105),表示OJ开始正常工作和结束正常工作的时间$
保证这些时间片段没有交集,且按时间顺序给出。

输出

如果Pasha能AK,输出祂最早能AK的时间点。否则输出-1。

样例

样例输入1

23 421 47 9

样例输出1

7

样例输入2

1511 4

样例输出2

-1

样例输入3

1511 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可以表示为n=xa+yb(a,b>0)
比如,如果x=2,y=3,第4(=20+31)和第17(=23+32=24+30)年就不是幸运的,而第18年就是幸运的。
而连续几年都幸运的年代就被称为黄金时代。
你的任务是写一个程序,找出最长的黄金年代,并且满足不早于第l年开始,不晚于第r年结束。如果不存在黄金年代(即[l,r]内都是不幸运的年份),输出0。

输入

唯一的一行包含4个正数x,y,l,r(2x,y1018,1lr1018)

输出

输出[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,b64,所以xayb的个数就6464=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(x1)。A和B轮流走,Bob先走。走一步的定义是将棋子保持不动或将棋子移到其相邻的点上(即两点间有边)。当Alice的棋子和Bob的棋子在同一个点上(A吃了B),游戏就结束了。Alice和Bob都很聪明,会做最好的选择(Alice希望最小化总步数而Bob希望最大化总步数)。请你写个程序算出游戏总步数。

输入格式

第一行2个正数n和x (2n2105, 2xn).
接下来的n1行,每行2个正数ab(1a,bn),表示树上的边。保证树合法。

输出格式

输出游戏总步数(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(2n5000),大序列元素个数.
第二行有n个整数a1,a2,...,an(1ai105) 大序列元素。

输出

输出符合条件的两个非空不相交子序列的长度和的最大值。

样例

样例输入1

41 2 4 5

样例输出1

4

样例输入2

662 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]更新答案,而且可以避免两个集合