• 18.10.24 考试总结


    我永远讨厌blutrex的题目靴靴

        

    这道题就是一道裸裸欧拉回路 但是由于我之前并没有写过...。 真的难受QAQ

    这道题首先想到建图是对于每一个简单词看作图上的边 某单词$ab$就建边$a -> b$ 如果单词可以反转再建一条反向边即可

    那么题目就转化成了给定若干边 求这个图是否可以"一笔画" 也就是说可不可以一遍$dfs$就可以跑完所有的边

    这是裸欧拉回路啊 所以这道题分为无向图和有向图两种 

    1.有向图

    欧拉回路有向图首先要看他是否成环 有两种情况

    一个是有固定的起点终点 起点的出度比入度多一 因为他不会回来 终点的出度比入度少一 因为最后会停留在这个点

    二是没有固定起点终点 那么这个时候每个点入度等于出度

    2.无向图 

    欧拉回路无向图和又想吐是类似的 

    有固定起点终点 这个时候起点终点的度数均为奇数 这两个点可以是起点终点or终点起点

    没有固定... 这个时候判断度数均为偶数即可

    那么最后还要判断是否可以跑完所有边 跑的时候把路径储存起来即可

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 8e5 + 5;
    int deg[N], tot = 1, head[N], tov[2 * N], nex[2 * N], id[2 * N];
    int stk[2 * N], top, n, m, in[N], out[N], T;
    bool vis[N];
    
    void add(int u, int v, int x) {
        
        tot ++; nex[tot] = head[u]; tov[tot] = v; head[u] = tot; id[tot] = x;
    }
    
    void dfs1(int u, int fre) {
        
        for(int i = head[u]; i; i = nex[i]) {
            int v = tov[i];
            if(vis[i]) continue;
            vis[i] = vis[i ^ 1] = true;
            dfs1(v, i);
        }
        stk[++ top] = id[fre];
    }
    
    int solve1( ) {
        
        int cnt = 0, st;
        scanf("%d%d",& n,& m);
        for(int i = 1;i <= m;i ++) {
            int u, v; scanf("%d%d",& u,& v); st = u;
            add(u, v, i); add(v, u, -i); deg[u] ++; deg[v] ++;
        } 
        for(int i = 1;i <= n;i ++) {
            if(deg[i] & 1) cnt ++, st = i;
        }
        if(cnt > 2 || cnt == 1) return !puts("NO");
        dfs1(st, 0); if(top != m + 1) return !puts("NO");
        puts("YES");
        for(int i = top - 1; i; i --) {
            printf("%d ", stk[i]);
        } puts("");
    }
    
    void dfs2(int u, int fre) {
        
        for(int i = head[u]; i; i = nex[i]) {
            int v = tov[i];
            if(vis[i]) continue;
            vis[i] = true;
            dfs2(v, i);
        }
        stk[++ top] = id[fre];
    }
    
    int solve2( ) {
        
        int cnt = 0, st = -1, ed = -1, U;
        scanf("%d%d",& n,& m);
        for(int i = 1; i <= m; i ++) {
            int u, v; scanf("%d%d",& u,& v); U = u;
            add(u, v, i); in[v] ++; out[u] ++;
        }
        for(int i = 1; i <= n; i ++)
            if(in[i] != out[i]) {
                cnt ++;
                if(in[i] == out[i] + 1) ed = i;
                if(in[i] + 1 == out[i]) st = i;
            }
        if((cnt != 0 && cnt != 2) || ((st == -1|| ed == -1) && cnt)) return !puts("NO");
        if(st == -1) st = U; dfs2(st, 0);
        if(top != m + 1) return !puts("NO");
        puts("YES");
        for(int i = top - 1;i >= 1;i --) {
            printf("%d ", stk[i]);
        } puts("");
    }
    
    int main( ) {
        
        freopen("merge.in", "r", stdin);
        freopen("merge.out", "w", stdout);
        scanf("%d",& T);
        if(T == 1) solve1( );
        else solve2( );
    }

    对不起第二题我真的不会:))

     

    我觉得这道题是因为考试的时候有点不想想第三题了然后就gg了 其实还是比较简单的,, 后悔sl

    我们用$dp[i]$表示初始以位置$i$作为逆序对靠前元素的位置的逆序对个数 这个东西可以用树状数组处理出来

    比如$1,5,4,2,6,3$那么$dp[3] = 2(4,2),(4,3) , dp[2] = 3(5, 4),(5, 2),(5, 3)...$

    我们可以推出一个很明显的性质 

    首先对于修改位置$i$的$a[i]$ 我们可以发现修改之后被重新排过的数的$dp$值变为$0$其余的数不变

    证明:

    因为他被重新排过 所以$i$后小于等于$a[i]$的数都是递增排列的 并且若他被排 那么比它更小的数也一定被排 且排在他的前面 至于没被排的数他们本来就不会和他产生逆序对 所以被排列的数的$dp$变为$0$

    至于没有被排的数 他们本来就比排的数要大 那么不管这些小的数如何排列 那么他们仍旧比他小 仍然构成逆序对且数量不变

    至于在$i$前的数 显然不会造成影响 因为前面的数与后面的不管是什么数相对位置都没有变化

    所以考虑每次修改过后在总的逆序对中减去他的$dp$值 再把被排列的数$dp$修改为$0$ 即可 这个可以使用链表维护(其实链表可以被卡 但是没有卡)

    至于更优秀的做法是使用线段树维护区间最小值 每次修改就在他后面的区间不断查询最小值修改 修改后把他自己删去 直到最小值大于当前值即可

    代码(链表)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 5;
    int c[N], n, a[N], m, dp[N], nex[N], pre[N];
    long long sum;
    
    int lowbit(int x) {return x & (-x);}
    
    int query(int pos) {
        
        int ans = 0;
        while(pos >= 1) {
            ans += c[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    void add(int pos) {
        
        while(pos <= n) {
            c[pos] ++;
            pos += lowbit(pos);
        }
    }
    
    void Init( ) {
        
        scanf("%d%d",& n,& m);
        for(int i = 1; i <= n; i ++) scanf("%d",& a[i]);
        for(int i = n; i >= 1; i --) {
            dp[i] = query(a[i] - 1); add(a[i]);
            sum += dp[i];
        }
        for(int i = 1;i <= n;i ++) nex[i] = i + 1, pre[i] = i - 1;
    }
    
    void Solve( ) {
        
        printf("%lld ", sum);
        for(int i = 1;i <= m;i ++) {
            int x; scanf("%d",& x);
            if(! dp[x]) {printf("%lld ", sum); continue;}
            for(int j = x;j <= n;j = nex[j])
                if(a[j] <= a[x])  nex[pre[j]] = nex[j], pre[nex[j]] = pre[j], sum -= dp[j], dp[j] = 0;
            printf("%lld ",sum);
        }
    }
    
    int main( ) {
        
        freopen("count.in", "r", stdin ) ;
        freopen("count.out", "w", stdout ) ;
        Init( );
        Solve( );
    }

    代码(线段树)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    
    const ll maxn = 2e5 + 5;
    
    ll n, m, ans = 0;
    
    ll read() {
        ll rt = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9') {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9') {
            rt = (rt << 1) + (rt << 3) + ch - '0';
            ch = getchar();
        }
        return rt * f;
    }
    
    struct Tree {
        ll vmin, pos;
    }t[maxn << 2];
    
    ll a[maxn], j[maxn], f[maxn], cnt[maxn], p[maxn], v[maxn], num;
    
    ll lowbit(ll x) {
        return x & (-x);
    }
    
    ll query(ll pos) {
        ll rt = 0;
        for (int i = pos; i >= 1; i-= lowbit(i)) {
            rt += f[i];
        }
        return rt;
    }
    
    void modify(ll pos, ll val) {
        for (int i = pos; i <= n; i += lowbit(i)) {
            f[i] += val;
        }
    }
    
    void update(ll o) {
        if (t[o << 1].vmin < t[o << 1 | 1].vmin) {
            t[o] = t[o << 1];
        } else {
            t[o] = t[o << 1 | 1];
        }
    }
    
    void build(ll o, ll lf, ll rg) {
        if (lf == rg) {
            t[o].pos = lf;
            t[o].vmin = a[lf];
            return ;
        }
        ll mid = (lf + rg) >> 1;
        build(o << 1, lf, mid);
        build(o << 1 | 1, mid + 1, rg);
        update(o);
    }
    
    void modify(ll o, ll lf, ll rg, ll pos, ll val) {
        if (lf == rg) {
            t[o].vmin = val;
            return ;
        }
        ll mid = (lf + rg) >> 1;
        if (pos <= mid) {
            modify(o << 1, lf, mid, pos, val);
        } else {
            modify(o << 1 | 1, mid + 1, rg, pos, val);
        }
        update(o);
    }
    
    Tree query(ll o, ll lf, ll rg, const ll L, const ll R) {
        if (L <= lf && rg <= R) {
            return t[o];
        }
        ll mid = (lf + rg) >> 1;
        Tree rt1, rt2;
        bool flag1 = 0, flag2 = 0;
        if (L <= mid) {
            flag1 = 1;
            rt1 = query(o << 1, lf, mid, L, R);
        }
        if (R > mid) {
            flag2 = 1;
            rt2 = query(o << 1 | 1, mid + 1, rg, L, R);
        }
        if (flag1 && flag2) {
            if (rt1.vmin < rt2.vmin) return rt1;
            else return rt2;
        } else if (flag1 && !flag2) {
            return rt1;
        } else if (!flag1 && flag2) {
            return rt2;
        }
    }
    
    int main() {
        freopen("count.in","r",stdin);
        freopen("count.out","w",stdout);
        n = read(), m = read();
        for (int i = 1; i <= n; i++) {
            a[i] = read();
        }
        for (int i = 1; i <= m; i++) {
            j[i] = read();
        }
        for (int i = n; i >= 1; i--) {
            ll now = query(a[i] - 1);
            cnt[i] = now;
            ans += cnt[i];
            modify(a[i], 1);
        }
        build(1, 1, n);
        printf("%lld ",ans);
        for (int i = 1; i <= m; i++) {
            num = 0;
            while (1) {
                Tree now = query(1, 1, n, j[i], n);
                if (now.vmin > a[j[i]]) break;
                num += cnt[now.pos];
                cnt[now.pos] = 0;
                modify(1, 1, n, now.pos, 1e9);
            }
            ans -= num;
            printf("%lld", ans);
            if (i != m) {
                printf(" ");
            } 
        }
        return 0;
    }
  • 相关阅读:
    Server SQL Modes
    Java 8 New Features
    Spring Boot 企业级应用开发实战 刘伟东-2018年3月第一版
    一步一步学Spring Boot 2 微服务项目实战
    Springboot揭秘-快速构建微服务体系-王福强-2016年5月第一次印刷
    深圳宝安图书馆官网错误 HTTP Status 500
    Springboot
    linux 操作 mysql 指定端口登录 以及启动 停止
    PHP 基础
    Magento 总结
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9844650.html
Copyright © 2020-2023  润新知