2023.02.11 模拟赛小结

2023.02.11 模拟赛小结

更好的阅读体验戳此进入

考的还是比较炸的,前两道已经想的差不多了,不过最后还是挂了。。

赛时思路

T1

#6178. 「美团 CodeM 初赛 Round B」景区路线规划

签到题,随便设一下状态转移一下即可,然后我大概就是想了很久总觉得这个玩意不符合无后效性,于是写了个十分复杂的分步考虑互相转移两个 DP 分别搞,一个是从该点起始再回到该点恰好时间的概率,然后再转移互相之间的概率,很 nt 的思路,甚至后面的互相转移的过程就是答案的式子,麻了麻了。

最后不知道时正确性的问题还是什么,总之只有 $ 10\texttt{pts} $。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;



template < typename T = int >
inline T read(void);

struct Edge{
    Edge* nxt;
    int to;
    int val;
    OPNEW;
}ed[26000];
ROPNEW;
Edge* head[110];

int N, M, K;
int c[110], h1[110], h2[110];
int deg[110][500];
ld expA(0.0), expB(0.0);
ld dp[110][500];
ld rdp[110][500];

int main(){
    freopen("park.in", "r", stdin);
    freopen("park.out", "w", stdout);
    N = read(), M = read(), K = read();
    for(int i = 1; i <= N; ++i)c[i] = read(), h1[i] = read(), h2[i] = read();
    for(int i = 1; i <= M; ++i){
        int s = read(), t = read(), v = read();
        head[s] = new Edge{head[s], t, v};
        head[t] = new Edge{head[t], s, v};
    }
    for(int p = 1; p <= N; ++p)
        for(int j = 0; j <= K; ++j)
            for(auto i = head[p]; i; i = i->nxt)
                    if(j + i->val + c[SON] <= K)++deg[p][j];
    for(int p = 1; p <= N; ++p){
        dp[p][c[p]] = 1.0 / (ld)N;
        for(int cost = 0; cost <= K; ++cost)
            for(auto i = head[p]; i; i = i->nxt)
                if(deg[p][cost] && deg[SON][cost + i->val + c[SON]] && cost + i->val * 2 + c[SON] + c[p] <= K)
                    dp[p][cost + i->val * 2 + c[SON] + c[p]] += dp[p][cost] * (1.0 / (ld)deg[p][cost]) * (1.0 / (ld)deg[SON][cost + i->val + c[SON]]);
    }
    memcpy(rdp, dp, sizeof dp);
    for(int p = 1; p <= N; ++p)
        for(int j = 0; j <= K; ++j)
            for(auto i = head[p]; i; i = i->nxt)
                if(deg[p][j] && j + i->val + c[SON] <= K)
                    rdp[SON][j + i->val + c[SON]] += dp[p][j] * (1.0 / (ld)deg[p][j]);
    for(int i = 1; i <= N; ++i)
        for(int j = 0; j <= K; ++j)
            // printf("dp[%d][%d] = %.5Lf, rdp[%d][%d] = %.5Lf\n", i, j, dp[i][j], i, j, rdp[i][j]),
            expA += (ld)h1[i] * rdp[i][j], expB += (ld)h2[i] * rdp[i][j];
    printf("%.5Lf %.5Lf\n", expA, expB);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}
/*
5 4 60
25 12 83
30 38 90
16 13 70
22 15 63
50 72 18
2 1 7
3 1 7
4 3 1
5 3 10
*/

T2

#6169. 相似序列

想到随机权值,想到哈希,然后考虑将其划分集合之后作个差直接在每个数的随机权值构成的 unordered_set 里查一下,然后想到这东西可能不是差一个数,于是就寄了,也想过直接前缀异或然后二分,但是判不了个数,也想过前缀哈希,但是判不了顺序。

所以最后挂了个暴力上去,$ 30\texttt{pts} $。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template < typename T = int >
inline T read(void);

int N, Q;
basic_string < int > A;

int main(){
    freopen("sequence.in", "r", stdin);
    freopen("sequence.out", "w", stdout);
    int T = read();
    while(T--){
        A.clear(); A += -1;
        N = read(), Q = read();
        for(int i = 1; i <= N; ++i)A += read();
        while(Q--){
            int a = read(), b = read(), c = read(), d = read();
            basic_string < int > s1(A.substr(a, b - a + 1)), s2(A.substr(c, d - c + 1));
            sort(s1.begin(), s1.end()), sort(s2.begin(), s2.end());
            bool diff(false);
            for(int i = 0; i < (int)s1.size(); ++i){
                if(s1.at(i) != s2.at(i)){
                    if(!diff)diff = true;
                    else{printf("NO\n"); break;}
                }
                if(i == (int)s1.size() - 1)printf("YES\n");
            }
        }
    }
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

/*
1
6 3
1 3 4 2 3 4
1 3 4 6
1 2 5 6
3 5 2 4
*/

T3

hihoCoder 1047 Random Tree

这个 OJ 挂了,所以链接也没用了。

给定无向带权完全图,等概率随机生成树,求任意两点间路径长度期望。

部分分很足,详细推导后可以拿到 $ 60\texttt{pts} $,剩下的正解分是一些根 Prufer 序列相关的奇怪东西,不会,当然或者也可以学习 @sssmzy 的高妙做法,发现答案与不连通要求两点的边的边权和一定成线性关系,且仅与 $ n $ 相关,由部分分可知。于是直接通过除法粗略计算斜率,然后实数二分提升精度即可。

正解

T1

如上所说,将多出来的转移删掉然后先枚举时间再枚举点,就可以直接消除后效性了。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;



template < typename T = int >
inline T read(void);

struct Edge{
    Edge* nxt;
    int to;
    int val;
    OPNEW;
}ed[26000];
ROPNEW;
Edge* head[110];

int N, M, K;
int c[110], h1[110], h2[110];
int deg[110][500];
ld expA(0.0), expB(0.0);
ld dp[110][500];
ld rdp[110][500];

int main(){
    // freopen("park.in", "r", stdin);
    // freopen("park.out", "w", stdout);
    N = read(), M = read(), K = read();
    for(int i = 1; i <= N; ++i)c[i] = read(), h1[i] = read(), h2[i] = read();
    for(int i = 1; i <= M; ++i){
        int s = read(), t = read(), v = read();
        head[s] = new Edge{head[s], t, v};
        head[t] = new Edge{head[t], s, v};
    }
    for(int p = 1; p <= N; ++p)
        for(int j = 0; j <= K; ++j)
            for(auto i = head[p]; i; i = i->nxt)
                    if(j + i->val + c[SON] <= K)++deg[p][j];
    // for(int p = 1; p <= N; ++p){
    //     dp[p][c[p]] = 1.0 / (ld)N;
    //     for(int cost = 0; cost <= K; ++cost)
    //         for(auto i = head[p]; i; i = i->nxt)
    //             if(deg[p][cost] && deg[SON][cost + i->val + c[SON]] && cost + i->val * 2 + c[SON] + c[p] <= K)
    //                 dp[p][cost + i->val * 2 + c[SON] + c[p]] += dp[p][cost] * (1.0 / (ld)deg[p][cost]) * (1.0 / (ld)deg[SON][cost + i->val + c[SON]]);
    // }
    // memcpy(rdp, dp, sizeof dp);
    for(int i = 1; i <= N; ++i)rdp[i][c[i]] = 1.0 / (ld)N;
    for(int j = 0; j <= K; ++j)
        for(int p = 1; p <= N; ++p){
            // rdp[p][c[p]] = 1.0 / (ld)N;
            
                for(auto i = head[p]; i; i = i->nxt)
                    if(deg[p][j] && j + i->val + c[SON] <= K)
                        rdp[SON][j + i->val + c[SON]] += rdp[p][j] * (1.0 / (ld)deg[p][j]);
        }
    for(int i = 1; i <= N; ++i)
        for(int j = 0; j <= K; ++j)
            // printf("dp[%d][%d] = %.5Lf, rdp[%d][%d] = %.5Lf\n", i, j, dp[i][j], i, j, rdp[i][j]),
            expA += (ld)h1[i] * rdp[i][j], expB += (ld)h2[i] * rdp[i][j];
    printf("%.5Lf %.5Lf\n", expA, expB);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}
/*
5 4 60
25 12 83
30 38 90
16 13 70
22 15 63
50 72 18
2 1 7
3 1 7
4 3 1
5 3 10
*/

T2

(权值、动态开点)主席树维护和哈希即可,这样就可以快速处理无序哈希,很朴素的思路,当然我是 sb 所以没想到。

code 懒得补了,主要欠的题太多,以后复习,主席树的时候或许再来写写

T3

代码咕了。

UPD

update-2023_02_11 初稿

posted @ 2023-02-15 19:10  Tsawke  阅读(23)  评论(0编辑  收藏  举报