【某次ks】20200512

<前言>

虽然全程睡觉,但是考得不错。

今早昨晚多晚睡我也就不说了,总之很困。就写了T1正解。


考试过程

T1

第一反应干草炸弹。

然后一个二分,判定的时候人傻了。直接计算不就好了写啥二分。

复杂度一算,单走一个树状数组,傻*。

然后睡了一场比赛。

T2

一开始题目出锅没看

后来不想看了

题解上一个二维最短路,s*。

T3

预处理+\(dp\),当时我tm直接睡着。

睡着前写了一个\(dfs\),实测5分;

T4

一看路径相关,反手一个点分。

然后发现有同色重复路径。

懒得管了,直接交,然后一分都没有。


考完之后我去接校车,结果等了半天发现不是今天(???)

然后就吃饭回寝

爽啦


Solution

[20200512普转提]T1 vr

大意

\(N\)个病毒,每个位置\(x_i\),生命值\(h_i\),每次攻击范围\([x-d,x+d]\)范围内病毒,伤害为\(W\),则最少几次杀死所有病毒。

Solution

因为要消灭所有病毒,最左边的病毒一定要被消灭,不妨直接以最左边病毒位置为左端点释放攻击。

这是个显而易见的贪心,然后直到消灭所有病毒即可。

\(Code:\)

#include<bits/stdc++.h>
#define N 200010
#define int long long
using namespace std;
int n, d, k;
struct node
{
    int x, h;
} a[N] = {};
int c[N] = {};
void inc(int x, int v)
{
    for(; x <= N - 10; x += x & (-x))
        c[x] += v;
}
int ask(int x)
{
    int sum = 0;
    for(; x; x -= x & (-x))
        sum += c[x];
    return sum;
}
inline int read()
{
    int s = 0, w = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-')
        c = getchar();
    if(c == '-')w = -1, c = getchar();
    while(c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}

inline bool cmp(node x, node y)
{
    return x.x < y.x;
}

signed main()
{
    freopen("vr.in", "r", stdin);
    freopen("vr.out", "w", stdout);
    n = read();
    d = read();
    k = read();
    for(int i = 1; i <= n; ++i)
        a[i].x = read(), a[i].h = read();
    sort(a + 1, a + n + 1, cmp);
    int tag = 1;
    long long sum = 0;
    for(int i = 1; i <= n; ++i)
    {
        int add = ask(i);
        if(a[i].h + add * k <= 0)continue;
        long long dec = (a[i].h + add * k + k - 1) / k;
        while(a[tag].x <= a[i].x + 2 * d && tag <= n)
            ++tag;
        inc(i, -dec);
        inc(tag, dec);
        sum += dec;
    }
    printf("%lld\n", sum);
    return 0;
}

[20200512普转提]T2 旅行花费

大意

\(n\)个城市,它们由\(m\)条双向道路连接,保证它们能够彼此到达。

\(i\)条道路连接\(u_i,v_i\),需要花费\(x_i\)个银币,耗费\(t_i\)秒的时间。每个城市处都有兑换银币处,第\(i\)个城市中你可以每次用\(1\)个金币兑换\(c_i\)个银币,可以兑换无限次,不过兑换\(1\)次需要花费\(d_i\)秒的时间。

你一开始在\(1\)号城市,有\(s\)个银币和无限多的金币,求到其它城市需要耗费的最小时间。

Solution

我们发现\(x_i\leq 50\)\(M\leq 100\)所以银币最多不过5000,再多也没用。

直接设置limit,然后把(位置,所剩银币)作为一个点去做二维最短路。

注意有很多细节比如如何获得答案?银币数的维护?

#include<bits/stdc++.h>
#define N 5010
#define fi first
#define se second
#define ll long long
#define mmp(x,y) make_pair(x,y)
using namespace std;

int n, m, s;
int c[N] = {}, d[N] = {};

inline int read()
{
    int s = 0, w = 1;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-')
        c = getchar();
    if(c == '-')w = -1, c = getchar();
    while(c <= '9' && c >= '0')
        s = (s << 3) + (s << 1) + c - '0', c = getchar();
    return s * w;
}

ll dis[55][N] = {};
int vis[55][N] = {};

struct Graph
{
    int net[N << 1], w[N << 1];
    int to[N << 1], ti[N << 1];
    int fl[N], len;
    inline void inc(int x, int y, int z, int t)
    {
        to[++len] = y;
        w[len] = z;
        ti[len] = t;
        net[len] = fl[x];
        fl[x] = len;
    }
} G;
priority_queue<pair<ll, pair<int, int> > >q;
void DJ(void)
{
    memset(vis, 0, sizeof(vis));
    memset(dis, 0x3f, sizeof(dis));
    dis[1][min(s, 5000)] = 0;
    q.push(mmp(-dis[1][min(s, 5000)], mmp(1, min(s, 5000))));
    while(!q.empty())
    {
        int t = q.top().se.fi;
        int s = q.top().se.se;
        q.pop();
        if(vis[t][s])continue;
        vis[t][s] = 1;
        if((dis[t][s] + d[t] < dis[t][min(s + c[t], 5000)]))
        {
            dis[t][min(s + c[t], 5000)] = (dis[t][s] + d[t]) * 1LL;
            q.push(mmp(-dis[t][min(5000, s + c[t])], mmp(t, min(5000, s + c[t]))));
        }
        for(int i = G.fl[t]; i; i = G.net[i])
        {
            int v = G.to[i], z = G.w[i], ti = G.ti[i];
            if(s < z)continue;
            if(dis[t][s] + ti < dis[v][s - z])
            {
                dis[v][s - z] = 1LL * (dis[t][s] + ti);
                q.push(mmp(-dis[v][s - z], mmp(v, s - z)));
            }
        }
    }
}

signed main()
{
    freopen("travel.in", "r", stdin);
    freopen("travel.out", "w", stdout);
    n = read();
    m = read();
    s = read();
    for(int i = 1; i <= m; ++i)
    {
        int x = read(), y = read();
        int z = read(), t = read();
        G.inc(x, y, z, t);
        G.inc(y, x, z, t);
    }
    for(int i = 1; i <= n; ++i)
    {
        c[i] = read();
        d[i] = read();
    }
    DJ();
    for(int i = 2; i <= n; ++i)
    {
        ll ans = 0x3f3f3f3f3f3f3f3f;
        for(int j = 0; j <= 5000; ++j)
            ans = min(ans, dis[i][j]);
        printf("%lld\n", ans);
    }
    return 0;
}

<后记>

后面的题目就鸽了吧。。

C题瞎搞有5分,D题我反手一个点分,明知道需要考虑重复色但是mode办法。

正解什么的根本没听(懂)。

posted @ 2020-05-13 14:50  云烟万象但过眼  阅读(92)  评论(0编辑  收藏  举报