• 18.8.21 考试总结


    今天也是考得西撇的一天。

    CDQ就是怎么写都写不对 搞了将近两个小时 cnm听见没cnm

    又开始出现时间不够 码力不足的问题了..

    果然还是思维完全不行啊.....

    这道题就是一个最大生成树的题 我之前从来都没有认真写过这个的题

    或者是我写了然后忘了.. 

    因为我们要求 i 到 j 所有路径经过点中最小值的最大值 所以考虑将点权从大到下排序

    然后建造一棵最大生成树 因为是从大到小添加入连通块的

    所以若是原来两个点没有联通 加上这个东西之后联通了

    那么就说明这个点是这两者路径中最小值的最大值 然后就可以统计答案了 

    连接两个点他们所属于的连通块 两块中的点可以两两组合 那么路径就是两块的size之积再乘以点权

    最后答案要×2 因为 算了f( i , j )和f( j , i )

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e6 + 5;
    int n,fa[N],m,head[N],tov[2 * N],nex[2 * N];
    int tot,w[N],siz[N],nd[N];
    ll ans;
    
    void add(int u,int v) {
        
        tot ++;
        nex[tot] = head[u];
        head[u] = tot;
        tov[tot] = v;
    }
    
    bool cmp(const int & a,const int & b) {
        
        return w[a] > w[b];
    }
    
    int find_fa(int x) {
        return x == fa[x] ? x : fa[x] = find_fa(fa[x]);
    }
    
    int read( ) {
        
        int ans = 0,t = 1;
        char x; x = getchar( );
        while(x < '0' || x > '9') {
            if(x == '-') t = -1;
            x = getchar( );
        }
        while(x >= '0' && x <= '9') {
            ans = ans * 10 + x - '0';
            x = getchar( );
        }
        return ans * t;
    }
    
    int main( ) {
        
        freopen("zoo.in","r",stdin);
        freopen("zoo.out","w",stdout);
        scanf("%d%d",& n,& m);
        for(int i = 1;i <= n;i ++) scanf("%d",& w[i]);
        for(int i = 1;i <= m;i ++) {
            int u,v;
            scanf("%d%d",& u,& v);
            add(u,v); add(v,u);
        }
        for(int i = 1;i <= n;i ++) {
            siz[i] = 1;
            fa[i] = i; nd[i] = i;
        }
        sort(nd + 1,nd + n + 1,cmp);
        for(int j = 1;j <= n;j ++) {
            int u = nd[j];
            for(int i = head[u];i;i = nex[i]) {
                int v = tov[i];
                int uu = find_fa(u),vv = find_fa(v);
                if(w[v] < w[u] || uu == vv)
                  continue;
                ans += 1LL * w[u] * siz[uu] * siz[vv];
                fa[vv] = uu;
                siz[uu] += siz[vv];
            }
        }
        printf("%I64d",ans * 2);
    }

    这道题是可以用cdq的 我在考场上面就写得cdq 然而写挂了... 难受

    然后正解要简单得多 就是树状数组 由题目可以知道覆盖区间的长度是递增的

    那么对于一段区间[ a , b ] 画个图

    该区间能够完全覆盖的区间数 就是b向左的右端点数 - a向右的左端点数

    a那边表示有多少区间不能被完全覆盖 而b那边表示有多少个区间在b左边结束 即可能被覆盖

    然后就出现一个问题 为什么不会出现最下面这样的情况呢 这样子就会多减啊

    但是因为区间长度是递增的 所以在[ a , b ]之前是不会出现长度大于该区间的线段的 所以这个是正确的 

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 4 * 1e5 + 5;
    int T,n,ans[N],c1[N],cnt,m,c2[N],a[N];
    struct ques {
        int l,r,tim,del;
    }q[N],ins[N];
    
    void clear( ) {
        
        memset(ans,-1,sizeof(ans));
        memset(c2,0,sizeof(c2));
        memset(c1,0,sizeof(c1));
    }
    
    void init( ) {
        
        int tmp = 0,num = 0;
        for(int i = 1;i <= n;i ++) {
            int pos,opt;
            scanf("%d%d",& opt,& pos);
            if(opt == 0) {
                tmp ++;
                q[i].l = pos; q[i].r = pos + tmp; q[i].tim = i;
                if(q[i].tim<0) break;
                q[i].del = 1;
                ins[tmp].l = pos; ins[tmp].r = pos + tmp;
                a[++ num] = q[i].l; a[++ num] = pos + tmp;
            }
            else {
                q[i].l = ins[pos].l; q[i].r = ins[pos].r;
                q[i].del = -1; q[i].tim = i;
                if(q[i].tim<0) break;
            }
        }
        sort(a + 1,a + num + 1);
        m = unique(a + 1,a + num + 1) - a - 1; 
    }
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    void add1(int pos,int del) {
        
        while(pos <= m) {
            c1[pos] += del;
            pos += lowbit(pos);
        }
    }
    
    void add2(int pos,int del) {
        
        while(pos <= m) {
            c2[pos] += del;
            pos += lowbit(pos);
        }
    }
    
    int query1(int pos) {
        
        int ans = 0;
        while(pos >= 1) {
            ans += c1[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    int query2(int pos) {
        
        int ans = 0;
        while(pos >= 1) {
            ans += c2[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    
    void solve( ) {
        
        for(int i = 1;i <= n;i ++) {
            
            int pos1 = lower_bound(a + 1,a + m + 1,q[i].l) - a - 1;
            int pos2 = lower_bound(a + 1,a + m + 1,q[i].r) - a;
            if(q[i].del == 1) {
                int ans1 = query1(pos1); int ans2 = query2(pos2);
                ans[q[i].tim] = ans2 - ans1;
            }            
            add1(pos1 + 1,q[i].del); add2(pos2,q[i].del);
        }
    }
    
    int main( ) {
        
        freopen("segment.in","r",stdin);
        freopen("segment.out","w",stdout);
        scanf("%d",& T);
        while(T --) {
            cnt ++;
            clear( );
            scanf("%d",& n);
            init( );
            solve( );    
            printf("Case #%d:
    ",cnt);
            for(int i = 1;i <= n;i ++) {
                if(ans[i] != -1) {
                    printf("%d
    ",ans[i]);
                }
            }
        }
    }

    这道题其实是一道数学题

    emmmm就是很考思维  因为题目上说k < max(m,n) 我们假设m n 较大的那个是行数

    那么也就是说我们至少有一行是空着的 

    那么除了这一行 每一行都可以乱搞 然后这空的一行来擦屁股 总能使每一列都合法

    然而乱搞的每一行不一定合法啊 所以思路是一样的

    对于每一行都留一个空位剩下的空位乱搞 然后这个空位来擦屁股 

    最后还需要特判一下这一行有没有填满 填满了就空不出位置了 判断一下填满的这行合不合法就可以了

    但是这时候就会出现一个问题 我们的空行是被动填的 会不会出现最后的这一行不合法呢

    答案是否定的 有三种情况 两边长分别是  奇 奇    偶 偶   奇  偶

    对于每一个矩形 我们空出一行 

    1.奇 偶  

     绝对不合法  因为要合法 每一行每一列-1个数均为奇数个

    那么-1的个数 = 奇数行 * 奇数个每行 = 奇数  偶数列 * 奇数个每列 = 偶数 矛盾了 所以不可能合法

    2.偶 偶

    总共有-1 偶 * 奇 = 偶数个  那么除去最后一行 剩下奇数行 * 奇数个 = 奇数

    所以最后一行就有偶数 - 奇数 = 奇数个 肯定合法 

    3.奇 奇 和上面是一样的证明

    所以就这么搞搞就出来了

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e6 + 10;
    int n,m,k,num[N][2];
    ll ans = 1,poww[N],mod;
    
    void init( ) {
        poww[0] = 1;
        for(int i = 1;i <= 1000000;i ++) 
          poww[i] = poww[i - 1] * 2 % mod;
    }
    
    int main( ) {
        
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
        scanf("%d%d",& n,& m);
        scanf("%d",& k);
        int numm = 0;
        for(int i = 1;i <= k;i ++) {
            int x,y,c; numm ++; 
            scanf("%d%d%d",& x,& y,& c);
            num[x][0] ++; num[y][1] ++;
        }
        scanf("%I64d",& mod);
        init( );
        int tag = 0;
        if((m + n) % 2 == 1) {
            printf("0");
            return 0;
        }
        if(n < m) {
            swap(n,m); tag = 1;
        }
        if(m == 1) {
            printf("%I64d",poww[n - numm - 1]);
            return 0;
        }
        bool t = false;
        for(int i = 1;i <= n;i ++) {
            if(num[i][tag] == 0 && (! t)) {
                t = true;
                continue;
            }
            ans = ans * poww[m - 1 - num[i][tag]] % mod;
        }
        printf("%I64d",ans);
    }

    今天真的考得很撇!!!!!!!!太垃圾了

  • 相关阅读:
    kettle7.0数据库迁移(MySQL迁移到Postgresql,迁移过程中自动创建表结构)
    正向代理与反向代理区别
    MySQL存储引擎相关知识点
    设计模式-装饰器模式
    设计模式-策略模式
    算法—数据结构学习笔记(二)栈
    Spring Boot2.0学习笔记(一)
    关联容器——map
    迭代器
    C风格字符串
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9512515.html
Copyright © 2020-2023  润新知