CSP-S模拟16 (没有T3和T4)

不及时放代码是因为我懒,想最后再使用Markdown,它太麻烦了!

“你的朝六晚十,你的书山题海,一定一定,都是值得……”

 

A. 猜道路

我在干嘛?!一个Floyed就能解决的事情我先建了一个最小生成树再往上添边,每次对新添的两个点跑dij再用这个值去更新别的点,直接整了158行?!(想必是昨天的T2造成了心理阴影……)

Floyed


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 303;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;

int n, mp[maxn][maxn];
bool del[maxn][maxn];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

int main()
{  
    n = read();
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            mp[i][j] = read();
        }
    }
    bool fl = 1;
    for(int k=1; k<=n && fl; k++)
    {
        for(int i=1; i<=n && fl; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(i!=k && i!=j && j!=k)
                {
                    if(mp[i][k]+mp[k][j]<mp[i][j])
                    {
                        fl = 0; break;
                    }
                    if(mp[i][k]+mp[k][j]==mp[i][j]) del[i][j] = del[j][i] = 1;
                }
            }
        }
    }
    if(fl)
    {
        ll ans = 0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<i; j++)
            {
                if(!del[i][j]) ans += mp[i][j];
            }
        }
        printf("%lld\n", ans);
    }
    else printf("-1\n");
    
    return 0;
}
Mine
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 303;
const int N = 9e4 + 3;
const int inf = 0x3f3f3f3f;

int e[maxn][maxn], n, fa[maxn], cnt;
ll ans, dis[maxn][maxn];
bool ext[N], vis[maxn];
typedef pair<ll, int> paint;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int next, to, w;
}a[N];
int head[maxn], len;

void add(int x, int y, int w)
{
    a[++len].to = y; a[len].next = head[x]; a[len].w = w;
    head[x] = len;
}

struct edge 
{
    int u, v, w;
    bool operator < (const edge &T) const 
    {
        return w < T.w;
    }
}s[N];

int find(int x)
{
    if(x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}
void un(int x, int y) {fa[find(x)] = find(y);}

priority_queue<paint, vector<paint>, greater<paint> > q;
void dij(int st, ll dis[])
{
    for(int i=1; i<=n; i++) vis[i] = 0;
    dis[st] = 0;
    q.push(make_pair(dis[st], st));
    while(!q.empty())
    {
        int x = q.top().second; q.pop();
        if(vis[x]) continue;
        for(int i=head[x]; i; i=a[i].next)
        {
            int v = a[i].to;
            if(dis[v] > dis[x] + a[i].w)
            {
                dis[v] = dis[x] + a[i].w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
}

int main()
{  
    n = read();
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            e[i][j] = read();
        }
    }
    for(int i=1; i<n; i++)
    {
        for(int j=i+1; j<=n; j++)
        {
            s[++cnt] = {i, j, e[i][j]};
        }
    }
    sort(s+1, s+1+cnt);
    for(int i=1; i<=n; i++) fa[i] = i;
    int tot = 0;
    for(int i=1; i<=cnt; i++)
    {
        if(find(s[i].u) != find(s[i].v))
        {
            add(s[i].u, s[i].v, s[i].w); add(s[i].v, s[i].u, s[i].w);
            un(s[i].u, s[i].v);
            tot++; ext[i] = 1;
            ans += s[i].w;
            //printf("add:(%d, %d, %d)\n", s[i].u, s[i].v, s[i].w);
        }
        if(tot == n-1) {break;}
    }
    memset(dis, 0x3f, sizeof(dis));
    for(int i=1; i<=n; i++) dij(i, dis[i]);
    /*for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++) printf("dis[%d][%d] = %lld\n", i, j, dis[i][j]);
        printf("\n");
    }*/
    for(int i=1; i<=cnt; i++)
    {
        if(ext[i] || s[i].w == dis[s[i].u][s[i].v]) continue;
        //printf("cmp : %d %lld\n", s[i].w, dis[s[i].u][s[i].v]);
        if(s[i].w > dis[s[i].u][s[i].v]) 
        {
            printf("-1"); exit(0);
        }
        else
        {
            ans += s[i].w;
            //printf("add:(%d, %d, %d)\n", s[i].u, s[i].v, s[i].w);
            add(s[i].u, s[i].v, s[i].w); add(s[i].v, s[i].u, s[i].w);
            dij(s[i].u, dis[s[i].u]); dij(s[i].v, dis[s[i].v]);
            for(int j=1; j<=n; j++)
            {
                for(int k=1; k<=n; k++)
                {
                    if(dis[s[i].u][j]+dis[s[i].u][k] < dis[j][k])
                    {
                        dis[j][k] = dis[s[i].u][j]+dis[s[i].u][k];
                    }
                    if(dis[s[i].v][j]+dis[s[i].v][k] < dis[j][k])
                    {
                        dis[j][k] = dis[s[i].v][j]+dis[s[i].v][k];
                    }
                }
            }
        }
    }
    printf("%lld\n", ans);
    
    return 0;
}

 

B. 简单环

输出0就有60,同样是乱搞,我乱搞的方式就比较Sily……

先建了一棵搜索树,然后打算判断一下每个点只有一条返祖边,1没考虑到不一定相同起点只要覆盖次数超了就不行,2不会实现以上操作,最后打算把所有返祖边塞进去都输出,WA 11***

鹤题解去了,%%%Delov / lxhcr,才知道树上差分可以当场求子树和(权值),我只会事后再加---应用:暗之链锁(A层邀请赛4)---关于树上路径覆盖的套路居然没有想到树上差分,zzz

积累一个函数:minmax(a, b) 返回一个pair,其中first是较小值,second是较大值。

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 4;
const int N = 2e5 + 4;
const int inf = 0x3f3f3f3f;

int fa[maxn], dep[maxn], val[maxn], pre[maxn], n, m;
bool vis[maxn];
vector<int> ans, son[maxn], gr[maxn];
typedef pair<int, int> paint;
map<paint, int> Map;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct node 
{
    int next, to;
}a[N];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

void dfs1(int u, int f)
{
    vis[u] = 1;
    dep[u] = dep[f] + 1;
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == f) continue;
        if(!vis[v])
        {
            dfs1(v, u); val[u] += val[v]; son[u].push_back(v); fa[v] = u;
        }
        else if(dep[v] < dep[u])
        {
            val[u]++; val[v]--; gr[u].push_back(v);
        }
    }
}

void dfs2(int u)
{
    pre[u] = (val[u]==1) + pre[fa[u]];
    for(int v : gr[u]) if(pre[v]-pre[u] == dep[v]-dep[u])
    {
        ans.push_back(Map[minmax(u, v)]);
        int now = u, pt = fa[u];
        while(now != v) {ans.push_back(Map[minmax(now, pt)]); now = pt; pt = fa[now];}
    }
    for(int v : son[u]) dfs2(v);
}

int main()
{  
    n = read(); m = read();
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read();
        add(u, v); add(v, u);
        Map[minmax(u, v)] = i;
    }
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])
        {
            dfs1(i, 0); dfs2(i);
        }
    }
    int sz = ans.size();
    printf("%d\n", sz);
    sort(ans.begin(), ans.end());
    for(int i=0; i<sz; i++)
    {
        printf("%d ", ans[i]);
    }
    
    return 0;
}

 

C. 汉明距离

直接暴力75 pts   多项式什么的,emmm……我……我居然又咕了一个题……

 

D. 勇者的后缀

56 pts之后的所有点都MLE了,可持久化Trie都没炸内存**实测sring的函数真是yyds

幸好string可以sort,否则我发现我不知道字典序大小的比较规则了***zzz

1.字符串左对齐比较       2.字母无大小写对应关系时忽略大小写,‘B’ > 'A' 和 'a'       3.字母有大小写对应关系时,大写小于小写,比如 'A' < 'a'       4.前缀相等较长的更小(空格小于所有字符)

所以这题就是个LCP的板子?!

即使是板子它照样很鬼畜,本来打算鹤的,又不想鹤了***

posted @ 2022-10-03 12:01  Catherine_leah  阅读(20)  评论(0编辑  收藏  举报
/* */