P2474 [SCOI2008]天平 差分约束

神题,因为砝码的质量只有三种,所以,对于每一种关系,都有一个上下界,那么我们可以通过一个floyd来跑出各点之间的差值范围,然后暴力枚举出解
在爆枚过程中怎么判断是哪种情况呢
摘一下chen_zhe大佬的
若要满足 A + B &lt; C + D A+B&lt;C+D A+B<C+D,那么只要满足 A − C &lt; D − B A−C&lt;D−B AC<DB或者 A − D &lt; C − B A−D&lt;C−B AD<CB就可以了

如果 A − C &lt; D − B A−C&lt;D−B AC<DB一定成立,那么 max ⁡ ( A − C ) &lt; min ⁡ ( D − B ) \max(A-C)&lt;\min(D-B) max(AC)<min(DB),A−D<C−B同理

若要满足 A + B = C + D A+B=C+D A+B=C+D,那么只要满足 A − C = D − B A−C=D−B AC=DB或者 A − D = C − B A−D=C−B AD=CB就可以了

如果 A − C = D − B A−C=D−B AC=DB一定成立,那么 min ⁡ ( A − c ) = max ⁡ ( A − c ) = min ⁡ ( D − B ) = max ⁡ ( D − B ) \min(A-c)=\max(A-c)=\min(D-B)=\max(D-B) min(Ac)=max(Ac)=min(DB)=max(DB)

A − D = C − B A−D=C−B AD=CB同理, A + B &gt; C + D A+B&gt;C+D A+B>C+D同理

			if(mn[s1][i]>mx[j][B] || mn[B][i]>mx[j][A])
                c1++;      //A+B>i+j <=> i-A<B-j
            if(mn[i][A]>mx[B][j] || mn[i][B]>mx[A][j])
                c3++;      //i+j>A+B <=> i-A>B-j
            if((mn[A][i]==mx[A][i] && mn[j][B]==mx[j][B] && mn[A][i]==mn[j][B]) || 
            (mn[A][j]==mx[A][j] && mn[i][B]==mx[i][B] && mn[A][j]==mn[i][B]))
                c2++;     //由上可得

完整的

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 53;
int mx[maxn][maxn],mn[maxn][maxn];
int n,A,B,c1,c2,c3;
int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;++i)
    {
        char ch[maxn];
        scanf("%s",ch+1);
        for(int j=1;j<=n;j++)
        {
            if(ch[j]=='?')
            {
                mx[i][j]=2;
                mn[i][j]=-2;
            }
            else if(ch[j]=='+')
            {
                mx[i][j]=2;
                mn[i][j]=1;
            }
            else if(ch[j]=='-')
            {
                mx[i][j]=-1;
                mn[i][j]=-2;
            }
            else
            {
                mx[i][j]=mn[i][j]=0;
            }
        }
    }
    for(int k=1;k<=n;k++)
        for(int j=1;j<=n;j++)
            for(int i=1;i<=n;i++)
                if(i!=j&&i!=k&&k!=j)
                {
                    mx[i][j]=min(mx[i][k]+mx[k][j],mx[i][j]);
                    mn[i][j]=max(mn[i][k]+mn[k][j],mn[i][j]);
                }
    for(int i=1;i<=n;i++)
    {
        if(i==A||i==B)continue;
        for(int j=1;j<=n;j++)
        {
            if(i==j)continue;
            if(j==A||j==B)continue;
            if(mn[A][i]>mx[j][B]||mn[B][i]>mx[j][A])c1++;
            if((mn[A][i]==mx[A][i]&&mn[j][B]==mx[j][B]&&mn[A][i]==mn[j][B])||(mn[A][j]==mx[A][j]&&mn[i][B]==mx[i][B]&&mn[A][j]==mn[i][B]))c2++;
            if(mn[i][A]>mx[B][j]||mn[i][B]>mx[A][j])c3++;
        }
    }
    printf("%d %d %d",c1/2,c2/2,c3/2);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值