P2474 [SCOI2008]天平


不得不说人家省选题目出的就是有水平

开始一直没有搞懂题目到底什么意思 这句话是关键:只有结果保证惟一的选法才统计在内

也就是左边有很多种可能性 右边选出来有很多种可能性 必须是左边严格大于右边(可能性不相交)c1++

同理 那这样就好理解了 因为是大小关系 想到差分约束 因为我们要严格大于或者小于 所以要求最长路和最短路

之后枚举就行

#include
#include
#include
#include
#include
#include
using namespace std;
int n,s1,s2;
int dx[55][55],dn[55][55];
int main()
{
    scanf("%d%d%d",&n,&s1,&s2);
    char a[60];
    for(int i=1;i<=n;i++){
        scanf("%s",a);
        for(int j=0;j=1;
            }else if(a[j]=='-'){
                dx[i][j+1]=-1; dn[i][j+1]=-2; //i-j<=-1;i-j>=-2;
            }else {
                dx[i][j+1]=2;  dn[i][j+1]=-2; //i-j<=2; i-j>=-2;
            }
        }
    }
    
    
    for(int k=1;k<=n;k++)            //Floyd
        for(int i=1;i<=n;i++) {  
            if(i==k) continue;    
            for(int j=1;j<=n;j++){
                if(i==k || i==j) continue;
                dx[i][j]=min(dx[i][j],dx[i][k]+dx[k][j]);//上界求最短路
                dn[i][j]=max(dn[i][k]+dn[k][j],dn[i][j]);//下界求最长路 
            }
        }
    
    
    int c1=0,c2=0,c3=0;
    for(int i=1;i<=n;i++){                 //暴力枚举所有可能性  
        if(i==s1 || i==s2) continue;
        for(int j=1;jdx[j][s2] || dn[s2][i]>dx[j][s1])
                c1++;      //s1-i的最小值大于j-s2的最大值==>s1+s2>i+j
            if(dn[i][s1]>dx[s2][j] || dn[i][s2]>dx[s1][j])
                c3++;      //同理:i-s1>s2-j ==> i+j>s1+s2
            if((dn[s1][i]==dx[s1][i] && dn[j][s2]==dx[j][s2] && dn[s1][i]==dn[j][s2]) || 
            (dn[s1][j]==dx[s1][j] && dn[i][s2]==dx[i][s2] && dn[s1][j]==dn[i][s2]))
                c2++;     //关系确定且满足的点 
        }
    }
    printf("%d %d %d",c1,c2,c3);
    return 0;
}