zoukankan      html  css  js  c++  java
  • P2474 [SCOI2008]天平

    题目传送门

    Solution

    我们先考虑其中一个问题: (A+B>C+D)

    可以简单的移项得到: (A-C>D-B)(A-D>C-B)

    看到这里你可能还不知道是什么

    再看看数据范围 (4 leq n leq 50)

    我直接暴力

    说明我们可以找一些复杂度不太大而且和不等式有关的算法,比如差分约束

    但是普通的差分约束是用来求一组解的,而这里的解不唯一,所以我们可以选择维护元素之间的和差关系。

    (minn_{u,v})(u,v)(min{u-v})(maxx_{u,v})(u,v)(max{u-v}) ,然后就可以像差分约束一样跑最短路得到这两个数组即可。

    至于求最短路的方法,因为 (4leq nleq 50) 并且需要每两个点之间的 (minn,maxx) ,所以考虑用Floyd。


    其实这里应该贴代码的,但是我觉得应该要详细的说一下建图。

    1. +对应的是 (i>j ightarrow i-j>0) ,那么可以得到 (minn_{i,j}=1,maxx_{i,j}=1)
    2. -对应的是 (i<j ightarrow j-i>0) , 同理,可得 (minn_{i,j}=-2,maxx_{i,j}=-1)
    3. =对应的是 (i=j) ,显然是 (maxx_{i,j}=minn_{i,j}=0)
    4. ?没有对应,那我们就考虑题里本来的限制 (maxx_{i,j}=2,minn_{i,j}=-2)

    其实这里应该完结撒花的,但是我觉得应该再说一下判断。

    有三个问题:

    1. (A+B>C+D Leftrightarrow A-C>D-B Leftrightarrow A-D>C-B)
    2. (A+B=C+DLeftrightarrow A-C=D-BLeftrightarrow A-D=C-B)
    3. (A+B<C+DLeftrightarrow A-C<D-BLeftrightarrow A-D<C-B)

    枚举 (C,D) 即可

    Code

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    const int N=55;
    int n,a,b,ans1,ans2,ans3,maxx[N][N],minn[N][N];
    char ch[N];
    
    int main(){
        scanf("%d%d%d",&n,&a,&b);
        a--;b--;
        for(int i=0;i<n;i++){
            scanf("%s",ch);
            for(int j=0;j<n;j++)
                if(ch[j]=='='||i==j){
                    maxx[i][j]=minn[i][j]=0;
                }
                else if(ch[j]=='-'){
                    maxx[i][j]=-1;
                    minn[i][j]=-2;
                }
                else if(ch[j]=='+'){
                    maxx[i][j]=2;
                    minn[i][j]=1;
                }
                else if(ch[j]=='?'){
                    maxx[i][j]=2;
                    minn[i][j]=-2;
                }
        }
        for(int k=0;k<n;k++)
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    if(i!=j&&j!=k&&i!=j)
                        maxx[i][j]=min(maxx[i][j],maxx[i][k]+maxx[k][j]),
                        minn[i][j]=max(minn[i][j],minn[i][k]+minn[k][j]);
        for(int c=0;c<n;c++)
            for(int d=0;d<c;d++){
                if(c==a||c==b||d==a||d==b) continue;
                if(minn[a][c]>maxx[d][b]||minn[a][d]>maxx[c][b]) ans1++;
                else if((maxx[a][c]==minn[a][c]&&maxx[d][b]==minn[d][b]&&maxx[a][c]==minn[d][b])||(maxx[a][d]==minn[a][d]&&maxx[c][b]==minn[c][b]&&maxx[a][d]==minn[c][b])) ans2++;
    			else if(maxx[a][c]<minn[d][b]||maxx[a][d]<minn[c][b]) ans3++;
            }
        printf("%d %d %d
    ",ans1,ans2,ans3);
        return 0;
    }
    
  • 相关阅读:
    C#匿名类与dynamic关键字有意思的玩法
    C#中参数化查询速度慢的原因
    拉姆达表达式的一些常用知识
    git的学习
    yield return的使用。。。
    C# Cache缓存的应用
    C# 异步编程,async与await的简单学习
    SSH
    SSM搭建手册
    PLsql快捷键
  • 原文地址:https://www.cnblogs.com/jasony/p/13872570.html
Copyright © 2011-2022 走看看