SWUST-2019-11-10 训练赛解题报告

A - As Fast As Possible

 CodeForces - 701D

首先,明确一点,大巴车是可以回去接人的。

在这里,我们不难发现,为了达到最优解,那些还未坐车的“大部队”和坐了车的“先行部队”的距离S是固定的。

SWUST-2019-11-10 训练赛解题报告_第1张图片
画出对应的t-x图:

SWUST-2019-11-10 训练赛解题报告_第2张图片

我们可以列出一个方程组:


指的是总花费时间。

我们假设每个bus向前的花费时间是x,返回接学生花费时间是y,那么,最优解的情况是每一位学生都能上车一次,因为车的载客量是K,所以我们的tim是N除以K向上取整。

然后连立这两个方程就可以通过x、y之间的固定关系求解了。
 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
double L, v1, v2;
int N, K, tim;
int main()
{
    scanf("%d%lf%lf%lf%d", &N, &L, &v1, &v2, &K);
    tim = N / K + (bool)(N % K);
    double ans;
    double A = 1. * tim + 1. * (tim - 1.) * (v2 - v1) / (v2 + v1);
    double B = (v2 - v1) / A;
    ans = L / (B + v1);
    printf("%lf\n", ans);
    return 0;
}

 


B - Connecting Universities

 CodeForces - 701E

  一个树上的思维操作,跟结点的size有关哦(非一般size,是有效size)

就是给出2*K个点(一开始我竟然读成了两千个点),然后我们可以画图来看,能发现其中的某些规律。

SWUST-2019-11-10 训练赛解题报告_第3张图片

假设如图,红色的点是题目中说到 的2*K个点。

  那么如果要去找最优解,也就是应该这样配对{5, 6}、{1, 4}也可以是{1, 6}、{5, 4}。那么,我们可以从每条边产生的贡献角度来考虑这个问题,1-2这条边要贡献一次,3-5、2-3的边也是会贡献一次,然后为了达成最优解,2-4这条边必须贡献两次,4-6也是必须贡献一次才可以。所以我们不如去看如何处理每条边的贡献。

  那么问题似乎被简化了,我们把每个结点的入度的边等效给结点上面去,(代表了3这号点的代表边是2-3),3的子树当中有一个标记点;2的子树中有3个,但是呢一共就只有4个点,所以其实1-2的边只用了4-3=1次。我们要考虑目前点的size和2*K-size的关系。
  所以,这道题简化一下,就是求树的子结点(包括本身)的有效结点个数,dfs的O(N)搜索即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, K, head[maxN], cnt, siz[maxN] = {0};
bool op[maxN] = {false};
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN<<1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
ll ans = 0;
void dfs(int u, int fa)
{
    siz[u] += op[u];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
    ans += min(siz[u], 2 * K - siz[u]);
}
inline void init()
{
    cnt = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    scanf("%d%d", &N, &K);
    init();
    for(int i=(K<<1), x; i>=1; i--)
    {
        scanf("%d", &x); op[x] = true;
    }
    for(int i=1, u, v; i

 


C - Little Boxes

 HDU - 6225

  特地卡了

long long

这两个定义方式,看很多人写的是大数,但是,实际上使用

__int128

就可以解决这个问题了。(很多编译器不支持__int128)但是测评机支持。

__int128的读入,需要使用自定义读入。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
__int128 A, B, C, D, sum;
inline __int128 read()
{
    __int128 x = 0;
    char ch = getchar();
    while(ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x;
}
inline void out(__int128 x)
{
    if(x > 9) out(x / 10);
    putchar(x % 10 + '0');
}
int main()
{
    int T; scanf("%d", &T);
    getchar();
    while(T--)
    {
        A = read(); B = read(); C = read(); D = read();
        sum = A + B + C + D;
        out(sum); puts("");
    }
    return 0;
}

 


D - Cube Stacking

 POJ - 1988

【种类并查集基础】

首先,我们来推一下样例,样例就是把1号结点放在6上面,把2号结点放在4上面,然后把4号结点放在6这个树上面,我们来看一下:

SWUST-2019-11-10 训练赛解题报告_第4张图片

我们建立反向树,其实就是一个种类并查集的过程了。

我们一开始的时候,看向只有2、4结点的时候,是4结点权值为0,2结点权值为1(因为它下面的子树有一个结点),然后再接着合并的时候,4号结点得到了6号结点的size=2,然后2号结点被跟着更新。

(POJ对头文件的限制,会让一部分头文件变成CE)。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
//#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e4 + 5;
int Q, root[maxN], siz[maxN] = {0}, sum[maxN];
int fid(int x)
{
    if(x == root[x]) return x;
    int fa = root[x];
    root[x] = fid(root[x]);
    siz[x] = siz[x] + siz[fa];
    return x = root[x];
}
void Mix(int x, int y)  //把x这一列放到y这一列的上面去
{
    int u = fid(x), v = fid(y);
    if(u == v) return;
    siz[u] = sum[v];
    root[u] = v;
    sum[v] += sum[u];
}
inline void init()
{
    for(int i=1; i

 


E - Rank of Tetris

 HDU - 1811

  我们可以首先看到题,可以先去处理相等的,也就是“=”号结点,不难发现,他们应当缩成一个点,然后我们再去建边,利用拓扑排序的性质(或者有的同学自学了Tarjan)来判断有没有环,如果有环了,说明构成了冲突,如果从任意一个0度的点出发,且仅从一个点出发,跑一次,如果所有点跑完了,就是一个确定的,如果跑出来环了,跑不下去了,那么就是说明了构成了环了,产生冲突。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=10005;
int N, M, root[maxN], head[maxN<<2], cnt, point, degree[maxN];
bool flag;
map, bool> mp;
struct eddge
{
    int no, to;
    char state;
    eddge(int a=0, int b=0, char c=NULL):no(a), to(b), state(c) {}
}ship[maxN<<1];
struct node
{
    int nex, to, val;
    node(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
}edge[maxN<<1];
void addEddge(int u, int v, int val)
{
    edge[cnt]=node(head[u], v, val);
    head[u]=cnt++;
}
queue Q;
void init()
{
    flag=false;
    mp.clear();
    while(!Q.empty()) Q.pop();
    cnt=0;  point=N;
    memset(head, -1, sizeof(head));
    memset(degree, 0, sizeof(degree));
    for(int i=0; i1) flag=true;
        int now=Q.front();  Q.pop();
        for(int u=head[now]; u!=-1; u=edge[u].nex)
        {
            int v=edge[u].to;
            degree[v]--;
            if(degree[v]==0)
            {
                Q.push(v);
                point--;
            }
        }
    }
}
int main()
{
    while(scanf("%d%d", &N, &M)!=EOF)
    {
        init();
        for(int i=1; i<=M; i++)
        {
            scanf("%d %c %d", &ship[i].no, &ship[i].state, &ship[i].to);
            if(ship[i].state == '=')
            {
                mix(ship[i].no, ship[i].to);
            }
        }
        for(int i=1; i<=M; i++)
        {
            if(ship[i].state == '=') continue;
            if(ship[i].state == '<')
            {
                if(mp[make_pair(fid(ship[i].to), fid(ship[i].no))]) continue;
                mp[make_pair(fid(ship[i].to), fid(ship[i].no))]=true;
                addEddge(fid(ship[i].to), fid(ship[i].no), 1);
                degree[fid(ship[i].no)]++;
            }
            else
            {
                if(mp[make_pair(fid(ship[i].no), fid(ship[i].to))]) continue;
                mp[make_pair(fid(ship[i].no), fid(ship[i].to))]=true;
                addEddge(fid(ship[i].no), fid(ship[i].to), 1);
                degree[fid(ship[i].to)]++;
            }
        }
        for(int i=0; i0) printf("CONFLICT\n");
        else if(flag) printf("UNCERTAIN\n");
        else printf("OK\n");
    }
    return 0;
}


F - Mike and Shortcuts

 CodeForces - 689B

题意:有N个十字路口,我们是从十字路口1号出发,问到1~N这几号十字路口的最短举例,然后,对于每个十字路口,都有一个近路可以走,路径长度都是1,并且是单向边。最后输出从1出发到1~N这些点的最短举例。

我们可以直接建边,但是别忘了考虑,我们可以从i点回到i-1这个点的可能性,因为有可能回溯回来再走是更优的解。

所以,我们的做法就是去跑一个线形dp最短路即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, a[maxN], dp[maxN], head[maxN], cnt;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN<<2];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
void tp()
{
    queue Q;
    Q.push(1); dp[1] = 0;
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(dp[v] > dp[u] + 1)
            {
                dp[v] = dp[u] + 1;
                Q.push(v);
            }
        }
    }
}
int main()
{
    scanf("%d", &N);
    for(int i=1; i<=N; i++) head[i] = -1;
    for(int i=1; i<=N; i++)
    {
        scanf("%d", &a[i]);
        addEddge(i, a[i]);
        if(i < N) addEddge(i, i + 1);
        if(i > 1) addEddge(i, i-1);
    }
    memset(dp, INF, sizeof(dp));
    tp();
    for(int i=1; i<=N; i++) printf("%d ", dp[i]);
    puts("");
    return 0;
}

 

你可能感兴趣的:(周赛)