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\}\) ,然后就可以像差分约束一样跑最短路得到这两个数组即可。

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


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

  1. +对应的是 \(i>j\rightarrow i-j>0\) ,那么可以得到 \(minn_{i,j}=1,maxx_{i,j}=1\)
  2. -对应的是 \(i<j\rightarrow 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+D\Leftrightarrow A-C=D-B\Leftrightarrow A-D=C-B\)
  3. \(A+B<C+D\Leftrightarrow A-C<D-B\Leftrightarrow 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\n",ans1,ans2,ans3);
    return 0;
}
posted @ 2020-10-25 11:11  jasony_sam  阅读(80)  评论(0编辑  收藏  举报