Educational Codeforces Round 54 [Rated for Div. 2]

第一次打CF,听大佬说是这场是教育场,看时间比较合适就打了。
Educational Codeforces Round 54 [Rated for Div. 2]

A. Minimizing the String

1s, 256M
题意:给一个字符串,删一个字母,使得字典序最小
思路:找第一个前一个比后一个字母字典序大的位置记录下来,删掉就行。
AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>

using namespace std;
string s;
int n;

int main() {
    cin >> n;
    cin >> s;
    int mark = n-1;
    for(int i = 0; i < n-1; ++i) {
        if(s[i] > s[i+1]) {
            mark = i;
            break;
        }
    }
    for(int i = 0; i < n; ++i) {
        if(i == mark) continue;
            printf("%c", s[i]);
    }
    printf("\n");
    return 0;
}

B. Divisor Subtraction

2s, 256M
题意:给出一个数字n (2 \le n \le 10^{10}),进行下面三步操作:
1.若n == 0 结束运算
2.找n的最小质因子d
3.n-d并回到step1
输出进行了多少次运算。
思路:很明显,如果这个数本来就是质数,那么只需要1步:减去它自身。但是如果是非质数,如果直接模拟,到找到它变成质数再一步变0也肯定会T。观察几个数字我们发现,如果这个数是偶数,那它的最小质因子必然是2,而它-2之后还是偶数,那么操作步数必然是n/2;而如果是奇数,找第一个质因子(必然也是奇数),相减变成偶数,然后又回到循环-2的情况。
AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>

using namespace std;
typedef long long ll;

bool isprimer(ll n) {
    ll a = sqrt(n) + 1;
    for(ll i = 2; i < a; ++i)
        if(n % i == 0)
            return false;
    return true;
}

int main() {
    ll n;
    scanf("%lld", &n);
    ll cnt;
    if(!(n & 1)) {
        cnt = n / 2;
    }
    else {
        if(isprimer(n)) {
            cnt = 1;
        }
        else {
            for(ll i = 3; i < n; i +=2) {
                if(n % i == 0) {
                    if(isprimer(i)) {
                        n -= i;
                        break;
                    }
                }
            }
            cnt = n / 2 + 1;
        }
    }
    printf("%lld", cnt);
    return 0;
}

C. Meme Problem

1s, 256M
题意:给出一个非负整数d (0 \le d \le 10^3),问是否存在两个非负实数ab使得a + b = da * b = d

input
7
69
0
1
4
5
999
1000
output
Y 67.985071301 1.014928699
Y 0.000000000 0.000000000
N
Y 2.000000000 2.000000000
Y 3.618033989 1.381966011
Y 997.998996990 1.001003010
Y 998.998997995 1.001002005

思路:刚刚看到题的时候看到a + ba * b也是往数学上想了一点点,但是发现这个如果是Y的a和b必然是一个1~2的数字和d-2~d-1的数字,故二分WA到怀疑人生……
赛后:
可能是我数学太差了8,这个题应该利用初中数学的韦达定理构造一元二次方程orz……
因为我们知道
在一元二次方程ax^2 + bx + c = 0
有韦达定理:
x1 + x2 = -\frac{b}{a}
x1 * x2 = \frac{c}{a}
我们令x1 + x2 = x1 * x2 即令-\frac{b}{a} = \frac{c}{a}c = -b
构造一元二次方程,ax^2 + bx - b = 0,令a = 1
因为x1 + x2 = d-\frac{b}{a} = d-b = d
故可构造出仅有系数d的一元二次方程x^2 - dx + d = 0
如果\Delta < 0则无解;
\Delta ≥ 0那么就可以直接求解:x1 = \frac {d + \sqrt {d ^ 2 - 4 * d} } {2}x2 = \frac {d - \sqrt {d ^ 2 - 4 * d} } {2}

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
#define eps 1e-9

int main() {
    int T, d;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &d);
        double dd = (double)d;
        double delta = dd * dd - 4 * dd;
        if(delta < 0) {
            printf("N\n");
        }
        else {
            printf("Y %.9f %.9f\n", (dd + sqrt(delta))/2.0, (dd - sqrt(delta))/2.0);
        }
    }
    return 0;
}

D. Edge Deletion

2.5s, 256M
题意:给出一个n个点、m条边的无向图(无自环、无重边),1i点的最短路是d_{i},现在删掉一些边,若1i的最短路依旧是d_{i},那么称i是好点。现在需要你删去一些边,至多剩下k条边,使得好点的数量尽量的多。
(2 \le n \le 3 \cdot 10^5, 1 \le m \le 3 \cdot 10^5, n - 1 \le m, 0 \le k \le m)
第一行输出需要保留的边的条数e ( 0 \leq e \leq k),第二行输出保留的边的序号(按照输入顺序标号为1m

思路:可以证明按优先队列跑出来的dij树是可行的,因为每次对于已经选中的点,走的路径都是最短,所以对于一个点,最短路虽然有很多,但选中的那条一定是从开始就一直最短的。直接跑出来dij树,尽量删叶子结点,也就是从后往前删边(dij树从后往前删边就是从长往短删),其实这里不用倒着删,直接取dij跑出来的前min(k, n-1)条边即可。

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 3e5 + 5;
int n, m, k;
struct edge { int to, cost; };
map<P, int> mp;
vector<edge> G[maxn];
vector<int> vec, anslist;
bool vis[maxn], vis1[maxn];
ll d[maxn];
int pre[maxn];

void dij() {
    priority_queue<P, vector<P>, greater<P> > que;
    int v, l;
    for(int i = 1; i <= n; ++i)
        d[i] = INF;
    d[1] = 0;
    que.push(P(0, 1));
    while(!que.empty()) {
        P now = que.top();
        que.pop();
        v = now.second;
        vec.push_back(v);
        if(d[v] < now.first)
            continue;
        l = (int)G[v].size();
        for(int i = 0; i < l; ++i) {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost) {
                pre[e.to] = v;
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }
        }
    }
}

vector<int> findway(int v) {
    vector<int> way;
    int pr = pre[v];
    way.push_back(v);
    while(pr != 1) {
        way.push_back(pr);
        pr = pre[pr];
        if(vis1[pr])
            break;
        vis1[pr] = true;
    }
    way.push_back(pr);
    reverse(way.begin(), way.end());
    return way;
}

void solve() {
    int l_ = vec.size();
    int v, l, st, ed, id;
    for(int i = 1; i < l_; ++i) {
        v = vec[i];
        vector<int> way = findway(v);
        l = way.size();
        for(int j = 0; j < l - 1; ++j) {
            st = way[j], ed = way[j+1];
            id = mp[P(st, ed)];
            if(!vis[id]) {
                vis[id] = true;
                anslist.push_back(id);
            }
        }
        if(anslist.size() >= k)
            return;
    }
    return;
}

int main() {
    int fr, to, cost;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < m; ++i) {
        scanf("%d%d%d", &fr, &to, &cost);
        mp[P(fr, to)] = i + 1;
        mp[P(to, fr)] = i + 1;
        G[fr].push_back((edge){to, cost});
        G[to].push_back((edge){fr, cost});
    }
    dij();
    if(k > n-1)
        k = n-1;
    solve();
    printf("%d\n", k);
    for(int i = 0; i < k; ++i) {
        if(i != 0) printf(" ");
        printf("%d", anslist[i]);
    }
    return 0;
}

我丑陋的代码跑了1060ms……
附:队友跑了467ms的代码

E. Vasya and a Tree

2s, 256M
题意:给你一棵以1为根的有n个点的树,每个点的权值最初为0。有m个操作,每次操作有三个变量v_{i}, d_{i}, x_{i},操作为在v的距离v_{i} ≤ d_{i}的子树内所有节点权值 + x,最终统计树上每个点的权值。
思路:先从根1开始,跑一次dfs把树存下来,然后每次操作都跑dfs,路径超过d就返回 -> TLE on test 7
*TLE代码(好像是线段树/树状数组…待补)

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
struct node {
    int u, v;
}p[maxn];
vector<int> g[maxn], G[maxn];
ll cost[maxn];
int n, m;
bool vis1[maxn], vis[maxn];

void dfs(int v, int d, int x) {
    cost[v] += x;
    if(d == 0) return;
    for(int i = 0; i < (int)G[v].size(); ++i) {
        int u = G[v][i];
        if(!vis[u]) {
            vis[u] = true;
            dfs(u, d-1, x);
            vis[u] = false;
        }
    }
    return;
}

void CreateTree(int u) {
    for(int i = 0; i < g[u].size(); ++i) {
        int v = g[u][i];
        if(!vis1[v]) {
            vis1[v] = true;
            G[u].push_back(v);
            CreateTree(v);
        }
    }
    return ;
}

int main() {
    int v, d, x;
    scanf("%d", &n);
    for(int i = 0; i < n-1; ++i) {
        scanf("%d%d", &p[i].u, &p[i].v);
        g[p[i].u].push_back(p[i].v);
        g[p[i].v].push_back(p[i].u);
    }
    vis1[1] = true;
    CreateTree(1);
    scanf("%d", &m);
    for(int i = 0; i < m; ++i) {
        scanf("%d%d%d", &v, &d, &x);
        vis[v] = true;
        dfs(v, d, x);
        vis[v] = false;
    }
    for(int i = 1; i <= n; ++i) {
        if(i != 1) printf(" ");
        printf("%lld", cost[i]);
    }
    return 0;
}

F. Summer Practice Report

2s, 256M

G. Array Game

6s, 512M

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容