嘘~ 正在从服务器偷取页面 . . .

洛谷P2474 [SCOI2008]天平 题解


洛谷P2474 [SCOI2008]天平 题解

题目链接:P2474 [SCOI2008]天平

题意

你有 \(n\) 个砝码,均为 \(\mathtt{1g}\)\(\mathtt{2g}\) 或者 \(\mathtt{3g}\)。你并不清楚每个砝码的重量,但你知道其中一些砝码重量的大小关系。

你把其中两个砝码 \(A\)\(B\) 放在天平的左边,需要另外选出两个砝码放在天平的右边。

问:有多少种选法使得天平的左边重 (\(c_1\))、一样重 (\(c_2\))、右边重 (\(c_3\))?(只有结果保证唯一的选法才统计在内)

输入格式

第一行包含三个正整数 \(n,A,B(4\le n\le 50,~1\le A\ne B\le n)\),砝码编号为 \(1\sim n\)

以下 \(n\) 行包含重量关系矩阵,其中第 \(i\) 行第 \(j\) 个字符表示砝码 \(i\) 与砝码 \(j\) 之间的关系,其中加号 \(\mathtt{+}\) 表示砝码 \(i\) 比砝码 \(j\) 重,减号 \(\mathtt{-}\) 表示砝码 \(i\) 比砝码 \(j\) 轻,等号 \(\mathtt{=}\) 表示砝码 \(i\) 和砝码 \(j\) 一样重,问号 \(\mathtt{?}\) 表示二者的关系未知。保证关系矩阵满足反对称性,且存在一种情况符合该矩阵。

输出格式

输出一行,包含三个整数,即 \(c_1,c_2,c_3\)

\(n\) 很小,考虑枚举无序对 \((i,j)\)

因此我们就是要找有多少对这样的 \((i,j)\) 使得 \[ w_A + w_B > w_i + w_j \] \(<\)\(=\) 同理。

这个式子不是很好处理,于是移项,得 \[ w_A - w_i > w_j -w_B \] 根据小学数学可知 \[ (w_A - w_i)_{\min} > (w_j - w_B)_{\max} \] 于是考虑求出这两个东西

显然如果 \(A\)\(i\) 直接相连,那我们在读入的时候就可以判断

毕竟 \(w_i \le 3\) 也好处理,后面的 \(B\) 也是同理

如果不是直接相连,相信你也想到了,\(\mathtt{Floyd}\)

然后我们求一个最长路和最短路就好了

判断稍微长一些,其他都不难

时间复杂度 \(O(n^3)\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(65))

char s[N];
int n,s1,s2,c1,c2,c3;
int dx[N][N],dn[N][N];
void up(int &x,int y) { x < y ? x = y : 0;}
void down(int &x,int y) { x > y ? x = y : 0;}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> s1 >> s2;
    for(int i=1,l; i<=n; i++)
    {
        cin >> (s+1); l=strlen(s+1);
        for(int j=1; j<=l; j++)
            if(s[j]=='=' || i==j) dx[i][j]=dn[i][j]=0;
            else if(s[j] == '+') dx[i][j]=2,dn[i][j]=1;
            else if(s[j] == '-') dx[i][j]=-1,dn[i][j]=-2;
            else dx[i][j]=2,dn[i][j]=-2;
    }
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                down(dx[i][j],dx[i][k]+dx[k][j]),
                up(dn[i][j],dn[i][k]+dn[k][j]);
                
    for(int i=1; i<=n; i++) if(i!=s1 && i!=s2)
        for(int j=1; j<i; j++) if(j!=s1 && j!=s2)
        {
            // s1-i min > j-s2 max => s1+s2 > i+j
            if(dn[s1][i] > dx[j][s2] || dn[s2][i] > dx[j][s1]) ++c1;
            // i-s1 min > s2-j max =? i+j > s1+s2
            if(dn[i][s1] > dx[s2][j] || dn[i][s2] > dx[s1][j]) ++c3;
            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;
        }
    cout << c1 << ' ' << c2 << ' ' << c3 << '\n';
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/lydsy1077%3Blg2474.html


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录