zoukankan      html  css  js  c++  java
  • 2020-07-02 热身训练赛(二)

    A.边权为lcm的最小生成树(HDU 5922)

    题意:一共有n个节点,编号从1到n,若在两个节点之间连边,则边权为两节点权值的最小公倍数,求该图的最小生成树的边权之和。

    解:每个节点加到树里,需要使添加的边权最小,每个数字与1的最小公倍数是这个数字本身,因此为最小边权,所以只需要将每个节点与节点1相邻即可。此时的答案最小,为2~n的和,即$frac{(2+n)(n-1)}{2}$

    #include<iostream>
    #include<cstdio>
    using namespace std;
    long long n,ans;
    int main(){
        int T;
        scanf("%d",&T);
        for(int Case=1;Case<=T;Case++){
            scanf("%lld",&n);
            ans=(2+n)*(n-1)/2LL;
            printf("Case #%d: %lld
    ",Case,ans);
        }
        return 0;
    }

    B.HDU 5923

    C.不等式(HDU 5924)

    题意:给出两个整数$A,B(1leq Aleq Bleq 10^{18})$,求出有哪些整数对$C,D(Aleq C,Dleq B)$,满足$frac{A}{B} + frac{B}{A} leq frac{C}{D} + frac{D}{C}$。

    解:把$frac{A}{B}$看作一个整体,为w,$frac{C}{D}$也看作一个整体v(假设$Cgeq D$,如果$Dgeq C$,那么就令$v=frac{D}{C}$,实际上都是一个道理),那么不等式可以写为$w+frac{1}{w} leq v+frac{1}{v}$,因为C和D是A和B之间的值,所以$wgeq v$,且$w,vgeq 1$,由对号函数的图像可知,始终存在$w+frac{1}{w}geq v+frac{1}{v}$,所以只有当$w=v$时有$w+frac{1}{w}leq v+frac{1}{v}$,此时有$A=C,B=D或者A=D,B=C$。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int T;
    long long A,B;
    int main(){
        scanf("%d",&T);
        for(int Case=1;Case<=T;Case++){
            printf("Case #%d:
    ",Case);
            scanf("%lld%lld",&A,&B);
            if(A==B){
                puts("1");
                printf("%lld %lld
    ",A,B);
            }
            else {
                if(A>B)swap(A,B);
                puts("2");
                printf("%lld %lld
    %lld %lld
    ",A,B,B,A);
            }
        }
        return 0;
    }

    D.连通块(HDU 5925)

    题意:有个n*m的网格(长宽最大为$10^{9}$),有一些格子内有障碍(最多200个),问有多少四连通块,每个连通块内的格子数

    解:离散化,将行和列分开进行离散化,拿行来讲,就是每个有障碍的行都要抽出来,两个有障碍的行之间的空白行离散为1行,这样的一行有一个权值,就是它对应的原来的行数,同理,列也要这样离散,直到将网格图离散为最多200*200的大小,就可以bfs了,还要注意一点,一个障碍没有的情况容易出错,最好特判一下。这个题和19年12月csp的第二题好像,当时那个题也做出来了,就是代码写的好啰嗦(捂脸脸)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    #define maxn 210
    using namespace std;
    int T,num,px[maxn],py[maxn],cntx,cnty,ans,n,m;
    long long wx[maxn*2],wy[maxn*2],q[maxn*maxn*4];
    bool f[maxn*2][maxn*2];
    map<int,int>ox;
    map<int,int>oy;
    struct point{
        int x,y;
    }p[maxn];
    
    void hx(){
        for(int i=1;i<=num;i++){
            if(px[i]==px[i-1])continue;
            if(i==1&&px[i]!=1){
                cntx++;
                wx[cntx]=px[i]-1;
            }
            if(i!=1&&px[i]!=px[i-1]+1){
                cntx++;
                wx[cntx]=px[i]-px[i-1]-1;
            }
            cntx++;
            wx[cntx]=1;
            ox[px[i]]=cntx;
        }
        if(px[num]!=n){
            cntx++;
            wx[cntx]=n-px[num];
        }
    }
    
    void hy(){
        for(int i=1;i<=num;i++){
            if(py[i]==py[i-1])continue;
            if(i==1&&py[i]!=1){
                cnty++;
                wy[cnty]=py[i]-1;
            }
            if(i!=1&&py[i]!=py[i-1]+1){
                cnty++;
                wy[cnty]=py[i]-py[i-1]-1;
            }
            cnty++;
            wy[cnty]=1;
            oy[py[i]]=cnty;
        }
        if(py[num]!=m){
            cnty++;
            wy[cnty]=m-py[num];
        }
    }
    
    void dfs(int x,int y){
        q[ans]+=wx[x]*wy[y];
        f[x][y]=1;
        if(x>1&&!f[x-1][y])dfs(x-1,y);
        if(y>1&&!f[x][y-1])dfs(x,y-1);
        if(x<cntx&&!f[x+1][y])dfs(x+1,y);
        if(y<cnty&&!f[x][y+1])dfs(x,y+1);
    }
    
    void init(){
        memset(f,0,sizeof(f));
        memset(q,0,sizeof(q));
        ans=0;
        cntx=0;
        cnty=0;
    }
    
    int main(){
        scanf("%d",&T);
        for(int Case=1;Case<=T;Case++){
            init();
            scanf("%d%d",&n,&m);
            scanf("%d",&num);
            if(num==0){
                int e=0;
            }
            if(num==0){
                ans=1;
                printf("Case #%d:
    ",Case);
                printf("%d
    ",ans);
                long long www=1LL*n*m;
                printf("%lld",www);
                puts("");
                continue;
            }
            for(int i=1;i<=num;i++){
                scanf("%d%d",&p[i].x,&p[i].y);
                px[i]=p[i].x;py[i]=p[i].y;
            }
            sort(px+1,px+num+1);
            sort(py+1,py+num+1);
            hx();hy();
            
            for(int i=1;i<=num;i++){
                int x=ox[p[i].x];
                int y=oy[p[i].y];
                f[x][y]=1;
            }
            
            for(int i=1;i<=cntx;i++){
                for(int j=1;j<=cnty;j++){
                    if(!f[i][j]){
                        ans++;
                        dfs(i,j);
                    }
                }
            }
            printf("Case #%d:
    ",Case);
            printf("%d
    ",ans);
            sort(q+1,q+ans+1);
            for(int i=1;i<ans;i++)printf("%lld ",q[i]);
            printf("%lld
    ",q[ans]);
        }
        return 0;
    }

    E.连连看(HDU 5926)

    题意:给出一个连连看的初始状态,判断能否连一次

    解:只需要判断四面和内部是否有可以连的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    using namespace std;
    int a[31][31];
    bool flag;
    map<int,bool>vis;
    int main(){
        int T;
        int n,m;
        scanf("%d",&T);
        for(int Case=1;Case<=T;Case++){
            printf("Case #%d: ",Case);
            flag=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%d",&a[i][j]);
            vis.clear();
            for(int i=1;i<=m;i++){
                if(vis[a[1][i]])flag=1;
                vis[a[1][i]]=1;
            }
            if(flag){puts("Yes");continue;}
            vis.clear();
            for(int i=1;i<=m;i++){
                if(vis[a[n][i]])flag=1;
                vis[a[n][i]]=1;
            }
            if(flag){puts("Yes");continue;}
            vis.clear();
            for(int i=1;i<=n;i++){
                if(vis[a[i][1]])flag=1;
                vis[a[i][1]]=1;
            }
            if(flag){puts("Yes");continue;}
            vis.clear();
            for(int i=1;i<=n;i++){
                if(vis[a[i][m]])flag=1;
                vis[a[i][m]]=1;
            }
            if(flag){puts("Yes");continue;}
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(a[i][j]==a[i-1][j]&&i>1)flag=1;
                    if(a[i][j]==a[i+1][j]&&i<n)flag=1;
                    if(a[i][j]==a[i][j-1]&&j>1)flag=1;
                    if(a[i][j]==a[i][j+1]&&j<m)flag=1;
                }
            }
            if(flag){puts("Yes");continue;}
            if(!flag){puts("No");continue;}
        }
    }

    F.HDU 5927

    G.HDU 5928

    H.nand(HDU 5929)

    题意:定义一种位运算nand,满足$\ 0 nand 0=1 \ 0 nand1=1 \ 1 nand 0=1 \ 1 nand 1=0\ $。要求实现一个栈,可以向栈顶加元素(只为1或0),弹出栈顶元素,求从栈顶到栈底的元素nand和,把栈反转,每次查询要求输出nand和。

    解:用队列代替栈,反转操作就定义一个标记,把标记的1和0作为此时栈正或反的状态,添加元素和弹出元素就可以根据标记值决定加在队列头或者尾。求nand和时先看一下规律,发现再nand运算下,所有数字nand 0都得1,那么对于一个序列,从头nand过来,不管前面的值为多少,只要读到0,当前结果就为1。所以计算时只需要找到最后一个0的位置,把它当作1(如果只有一个0,而且在栈顶,就需要特判)。然后又发现$\ 1=1 \ 1 nand 1=0 \ 1 nand 1 nand 1=1 \ 1 nand 1 nand 1 nand 1=0\$可以发现奇数个1的nand和为1,偶数个1的nand和为0,就可以结合末尾1的个数来求总nand和了。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #define maxn 200010
    using namespace std;
    int q[maxn*2],id[maxn*2],qcnt[2],idcnt[2];
    bool flag=1;
    char s[10];
    int main(){
        freopen("Cola.txt","r",stdin);
        int T,x,n;
        scanf("%d",&T);
        for(int Case=1;Case<=T;Case++){
            qcnt[1]=idcnt[1]=200002;
            qcnt[0]=idcnt[0]=200003;
            flag=1;
            printf("Case #%d:
    ",Case);
            scanf("%d",&n);
            while(n--){
                scanf("%s",s);
                if(s[2]=='S'){
                    scanf("%d",&x);
                    if(flag)q[++qcnt[flag]]=x;
                    else q[--qcnt[flag]]=x;
                    if(x==0){
                        if(flag)id[++idcnt[flag]]=qcnt[flag];
                        else id[--idcnt[flag]]=qcnt[flag];
                    }
                }
                else if(s[2]=='P'){
                    if(q[qcnt[flag]]==0){
                        if(flag)idcnt[flag]--;
                        else idcnt[flag]++;
                    }
                    if(flag)qcnt[flag]--;
                    else qcnt[flag]++;
                }
                else if(s[2]=='V'){
                    flag=!flag;
                }
                else if(s[2]=='E'){
                    if(qcnt[1]<qcnt[0]){
                        puts("Invalid.");
                    }
                    else if(qcnt[0]==qcnt[1]){
                        printf("%d
    ",q[qcnt[0]]);
                    }
                    else if(idcnt[1]<idcnt[0]){
                        printf("%d
    ",(qcnt[1]-qcnt[0]+1)%2);
                    }
                    else if(idcnt[1]-idcnt[0]==0&&q[qcnt[flag]]==0){
                        printf("%d
    ",(qcnt[1]-qcnt[0])%2);
                    }
                    else{
                        printf("%d
    ",(abs(qcnt[!flag]-id[idcnt[!flag]])+1)%2);
                    }
                }
            }
        }
        return 0;
    }

    I.HDU 5930

    J.HDU 5931

    K.HDU 5932

  • 相关阅读:
    Codeforces.468C.Hack it!(构造)
    BZOJ.3227.[SDOI2008]红黑树tree(树形DP 思路)
    146
    145
    144
    143
    142
    141
    140
    139
  • 原文地址:https://www.cnblogs.com/thmyl/p/13227201.html
Copyright © 2011-2022 走看看