2022NOIPA层联测7

问题 A: 【2022NOIP联测710月11日】找(a)

一看到是个数学题还感觉挺恐怖,把式子写出来才发现它很水。

没开long long大样例跑不出来还以为T1又没了……然而幸好及时发现问题。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 2e5 + 8;
const ll mod = 998244353;

int n;
ll suma, sumb, sx1, sx2, fa[maxn], fb[maxn], ans, a[maxn], b[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++)
    {
        a[i] = read(); b[i] = read();
        fa[i] = a[i]*a[i]%mod; fb[i] = b[i]*b[i]%mod;
        suma = (suma + a[i]) % mod; sumb = (sumb + b[i]) % mod;
    }
    for(int i=1; i<=n; i++)
    {
        sx1 = (sx1 + fa[i]) % mod; sx2 = (sx2 + fb[i]) % mod;
    }
    for(int i=1; i<=n; i++)
    {
        ans = ((n-2)*fa[i]%mod + (n-2)*fb[i]%mod) % mod;
        ans = (ans + sx1 + sx2) % mod;
        ll del = (2*a[i]%mod*(suma-a[i]+mod)%mod+2*b[i]%mod*(sumb-b[i]+mod)%mod)%mod;
        ans = (ans+mod-del)%mod;
        printf("%lld\n", ans);
    }
    
    return 0;
}
View Code

 

问题 B: 【2022NOIP联测710月11日】女(b)

第一版暴力是把所有黑点的集合记下来,对每一个是黑点的点求距离,找距离最小的。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 6;
const int inf = 0x3f3f3f3f;

int n, q, dep[maxn], siz[maxn], son[maxn], fa[maxn], top[maxn];
set<int> s;

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[maxn<<1];
int head[maxn], len;

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

void find_heavy_edge(int u, int fat, int depth)
{
    dep[u] = depth;
    fa[u] = fat;
    son[u] = 0;
    siz[u] = 1;
    int maxsize = 9;
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(dep[v]) continue;
        find_heavy_edge(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}

void connect_heavy_edge(int u, int ancestor)
{
    top[u] = ancestor;
    if(son[u])
    {
        connect_heavy_edge(son[u], ancestor);
    }
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa[u] || v == son[u]) continue;
        connect_heavy_edge(v, v);
    }
}

int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}

int main()
{   
    n = read(); q = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    find_heavy_edge(1, 1, 1);
    connect_heavy_edge(1, 1);
    while(q--)
    {
        int opt = read();
        if(opt == 1)
        {
            int x = read();
            if(s.find(x) != s.end()) s.erase(x);
            else s.insert(x);
        }
        else 
        {
            int x = read(); 
            if(s.empty()) {printf("-1\n"); continue;}
            int ans = inf;
            for(int y : s)
            {
                ans = min(ans, dep[x]+dep[y]-2*dep[LCA(x,y)]);
            }
            printf("%d\n", ans);
        }
    }
    
    return 0;
}
TLE 10

比较优化的暴力是把子树的最优解放进set里,然后直接跳father:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 6;
const int inf = 0x3f3f3f3f;

int n, q, fa[maxn], ans;
bool vis[maxn];
multiset<int> s[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;
}

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

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

void dfs(int x, int f)
{
    fa[x] = f;
    for(int i=head[x]; i; i=a[i].next)
    {
        int y = a[i].to;
        if(y == fa[x]) continue;
        dfs(y, x);
    }
}

void update0(int x)
{
    int tp = 0;
    while(x)
    {
        s[x].erase(s[x].find(tp));
        tp++; x = fa[x];
    }
}

void update1(int x)
{
    int tp = 0;
    while(x)
    {
        s[x].insert(tp);
        tp++; x = fa[x];
    }
}

void query(int x)
{
    int tp = 0; ans = inf;
    while(x)
    {
        if(s[x].size()) ans = min(ans, (*s[x].begin())+tp);
        x = fa[x]; tp++;
    }
    if(ans == inf) ans = -1;
}

int main()
{
    n = read(); q = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    dfs(1, 0);
    while(q--)
    {
        int opt = read();
        if(opt == 1)
        {
            int x = read();
            if(vis[x] == 1) {vis[x] = 0; update0(x);}
            else {vis[x] = 1; update1(x);}
        }
        else 
        {
            int x = read();
            query(x);
            printf("%d\n", ans);
        }
    }
    
    return 0;
}
TLE 40

直接bfs:(本来第一个想到bfs然后以为它太慢。。笑死了开什么优化)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 6;
const int inf = 0x3f3f3f3f;

int n, q, sum;
bool col[maxn], vis[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;
}

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

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

int bfs(int stx)
{
    int cnt = 0;
    queue<pair<int, int> > q;
    memset(vis, 0, sizeof(vis));
    q.push(make_pair(stx, cnt));
    while(!q.empty())
    {
        pair<int, int> x = q.front();
        q.pop();
        if(col[x.first] == 1) return x.second;
        vis[x.first] = true;
        for(int i=head[x.first]; i; i=a[i].next)
        {
            int to = a[i].to;
            if(!vis[to])
            {
                if(col[to]) return x.second+1;
                q.push(make_pair(to, x.second+1));
            }
        }
    }
    return -1;//useless but because of warning
}

int main()
{   
    n = read(); q = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    while(q--)
    {
        int opt = read();
        if(opt == 1)
        {
            int x = read();
            if(!col[x]) sum++;
            else sum--;
            col[x] ^= 1;
        }
        else 
        {
            int x = read();
            if(!sum) printf("-1\n");
            else printf("%d\n", bfs(x));
        }
    }
    
    return 0;
}
TLE 90

 

问题 C: 【2022NOIP联测710月11日】朋(c)

每一个左边的点都能找到匹配,所以对左边的点的匹配生成排列,判断一下and和是谁:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 109;
const int inf = 0x3f3f3f3f;

int n, m, ext[133], num;
bool vis[maxn];
vector<int> v[maxn], w[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;
}

void dfs(int a, int n)
{
    if(a > n)
    {
        if(num <= 127) ext[num] = 1;
        return;
    }
    int sz = v[a].size();
    for(int i=0; i<sz; i++)
    {
        int to = v[a][i];
        if(vis[to]) continue;
        vis[to] = 1;
        int now = num;
        if(a == 1) num = w[a][i];
        else num &= w[a][i];
        dfs(a+1, n);
        vis[to] = 0;
        num = now;
    }
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=m; i++)
    {
        int x = read(), y = read(), z = read();
        v[x].push_back(y); w[x].push_back(z);
    }
    dfs(1, n);
    for(int i=0; i<=127; i++)
    {
        printf("%d", ext[i]);
    }
    
    return 0;
}
TLE 20

当初学网络流的初心就是让它在这种时候派上用场,然而我并不会活学活用(样例都过不了但是可以A就诡异),鹤的,from gtm 1514:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 109;
const int inf = 0x3f3f3f3f;

int n, m, s, t, len=1, head[2010], head2[2010], dis[2010];

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 v, w, val, next, weight;
}a[2000010];

void add(int u, int v, int w, int weight)
{
    a[++len].v = v; a[len].next = head[u]; head[u] = len;
    a[len].val = w; a[len].w = w;
    a[len].weight = weight;
}
queue<int> q;
bool bfs(int st, int k)
{
    for(int i=0; i<=2*n+1; i++) head2[i] = head[i], dis[i] = 0;
    q.push(st); dis[st] = 1;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        for(int i=head[x]; i; i=a[i].next)
        {
            if((k&a[i].weight)==k&&!dis[a[i].v]&&a[i].w)
            {
                dis[a[i].v] = dis[x]+1;
                if(a[i].v == t)
                {
                    while(!q.empty()) q.pop();
                    return true;
                }
                q.push(a[i].v);
            }
        }
    }
    return false;
}

int dfs(int x, int flow, int k)
{
    if(x == t) return flow;
    int sum = 0;;
    for(int &i=head2[x]; i; i=a[i].next)
    {
        if((k&a[i].weight)==k&&dis[a[i].v]==dis[x]+1&&a[i].w)
        {
            int ret = dfs(a[i].v, min(flow, a[i].w), k);
            if(ret)
            {
                a[i].w -= ret; a[i^1].w += ret;
                sum += ret; flow -= ret;
                if(!flow) return sum;
            }
            else dis[a[i].v] = -1;
        }
    }
    return sum;
}

int dinic(int k)
{
    int ans = 0;
    while(bfs(s, k)) ans += dfs(s, 2147483647, k);
    return ans;
}

int main()
{
    n = read(); m = read(); t = 2*n+1;
    for(int i=1; i<=m; i++)
    {
        int u = read(), v = read(), w = read();
        add(u, v+n, 1, w); add(v+n, u, 0, w);
    }
    for(int i=1; i<=n; i++)
    {
        add(s, i, 1, 127); add(i, s, 0, 127);
        add(i+n, t, 1, 127); add(t, i+n, 0, 127);
    }
    for(int i=0; i<128; i++)
    {
        for(int j=2; j<=len; j++) a[j].w = a[j].val;
        int ans = dinic(i);
        if(ans == n) printf("1");
        else printf("0");
    }
    
    return 0;
}
网络流居然A了

 

问题 D: 【2022NOIP联测710月11日】友(d)

对每一个点维护以它为根的子树的合法决策放进set,合法的条件是a递减b也递减,这里的a,b是求和之后的也就是suma,sumb,子树向上合并时先满足b递减的条件,如果前驱(b更大)而a更小不满足单调性,当前决策不优,删掉,如果后继(b更小)而a更大那么这个后继不优,删掉,继续找下一个后继直到找到一个不用被删了的为止。

最后b最大的s[x].begin()就是以x为根的答案。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1003;
const int inf = 0x3f3f3f3f;

int n, m, a[maxn], b[maxn];
ll ans;

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;
}e[maxn<<1];
int head[maxn], len;

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

struct cho 
{
    ll a, b;
    bool operator < (const cho &T) const 
    {
        return b > T.b;
    }
};
vector<cho> ve;
set<cho> s[maxn], sp;
set<cho>::iterator it;

void dfs(int x, int fa)
{
    s[x].insert((cho){a[x], b[x]});
    for(int i=head[x]; i; i=e[i].next)
    {
        int y = e[i].to;
        if(y == fa) continue;
        dfs(y, x);
        sp.clear();
        for(auto p : s[x])
        {
            sp.insert(p);
        }
        for(auto p : sp)
        {
            for(auto q : s[y])
            {
                if(p.a + q.a > m) continue;
                cho r = (cho){p.a+q.a, p.b+q.b};
                s[x].insert(r);
                it = s[x].lower_bound(r);
                if(it != s[x].begin())
                {
                    auto dr = it; dr--;
                    if((*it).a > (*dr).a) s[x].erase(it);
                    else 
                    {
                        dr++; dr++;
                        for(; dr!=s[x].end(); dr++)
                        {
                            if((*it).a < (*dr).a) ve.push_back(*dr);
                            else break;
                        }
                        if(ve.size())
                        {
                            for(auto f : ve) s[x].erase(f);
                            ve.clear();
                        }
                    }
                }
                else 
                {
                    auto dr = it; dr++;
                    for(; dr!=s[x].end(); dr++)
                    {
                        if((*it).a < (*dr).a) ve.push_back(*dr);
                        else break;
                    }
                    if(ve.size())
                    {
                        for(auto f : ve) s[x].erase(f);
                        ve.clear();
                    }
                }
            }
        }
    }
    it = s[x].begin();
    ans = max(ans, (*it).b);
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=n; i++)
    {
        a[i] = read(); b[i] = read();
    }
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    dfs(1, 0);
    printf("%lld\n", ans);
    
    return 0;
}
TLE 60

好像又觉得套个点分治,也没什么好说的……

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1003;
const int N = 1e4 + 6;
const int inf = 0x3f3f3f3f;

int n, m, a[maxn], b[maxn], siz[maxn], mx[maxn], sum, root;
int dfn[maxn], dfnr[maxn], id[maxn], tim;
bool vis[maxn];
ll f[maxn][N], ans;

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;
}e[N];
int head[maxn], len;

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

void findroot(int x, int fa)
{
    siz[x] = 1; mx[x] = 0;
    for(int i=head[x]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(v == fa || vis[v]) continue;
        findroot(v, x);
        siz[x] += siz[v];
        mx[x] = max(mx[x], siz[v]);
    }
    mx[x] = max(mx[x], sum-siz[x]);
    if(mx[x] < mx[root]) root = x;
}

void dfs(int x, int fa)
{
    dfn[x] = ++tim; id[tim] = x;
    for(int i=head[x]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(v == fa || vis[v]) continue;
        dfs(v, x);
    }
    dfnr[dfn[x]] = tim;
}

void calc(int x)
{
    tim = 0;
    dfs(x, 0);
    for(int i=1; i<=tim+1; i++)
    {
        for(int j=0; j<=m; j++) f[i][j] = -inf;
    }
    f[1][0] = 0;
    for(int i=1; i<=tim; i++)
    {
        if(i + 1 <= dfnr[i])
        {
            int now = id[i];
            for(int j=0; j<=m-a[now]; j++)
            {
                f[i+1][j+a[now]] = max(f[i+1][j+a[now]], f[i][j]+b[now]);
            }
        }
        for(int j=0; j<=m; j++)
        {
            int now = id[i];
            if(j + a[now] <= m) f[dfnr[i]+1][j+a[now]] = max(f[dfnr[i]+1][j+a[now]], f[i][j]+b[now]);
            f[dfnr[i]+1][j] = max(f[dfnr[i]+1][j], f[i][j]);
        }
    }
    for(int i=0; i<=m; i++) ans = max(ans, f[tim+1][i]);
}

void solve(int x)
{
    calc(x); vis[x] = true;
    for(int i=head[x]; i; i=e[i].next)
    {
        int v = e[i].to;
        if(vis[v]) continue;
        sum = siz[v]; root = 0;
        findroot(v, 0); solve(root);
    }
}

int main()
{
    n = read(); m = read();
    for(int i=1; i<=n; i++) a[i] = read(), b[i] = read();
    for(int i=1; i<n; i++)
    {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }
    mx[0] = sum = n;
    findroot(1, 0);
    solve(root);
    printf("%lld\n", ans);
    
    return 0;
}
code

 

posted @ 2022-10-11 15:46  Catherine_leah  阅读(41)  评论(5编辑  收藏  举报
/* */