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

    题面

    更好的阅读体验?

    Solution

    题目中的 “(+)” 和 “(-)” 都蕴含着大小关系,所以考虑差分约束。

    对于每两个砝码之间有四种情况,我们可以分别列出他们的不等关系

    • 如果是 (i = j), 那么有 (0 le i - j le 0)
    • 如果是 (i > j),那么有 (1 le i - j le 2)
    • 如果是 (i < j), 那么有 (-2 le i - j le -1)
    • 如果是 (?),那么有 (-2 le i - j le 2)

    不等式的范围取决于两个砝码 (i,j) 极限时能取的的情况

    我们要知道在所有这些约束条件都满足的情况下,两个砝码之差的范围

    那么需要一个最大值和最小值。

    我们知道差分约束中最长路可以求最小值,最短路可以求最大值,那么根据上面的不等关系拆开建边即可。

    这里采用 ( ext{Floyd}) 求最短路,这样两点之间的差也好表示:

    (Dis_{i,j})(j - i) 可取的最小值, (dis_{i,j})(j - i) 可取的最大值,即

    [Dis_{i,j} le j-i le dis_{i,j} ]

    为什么要求两个砝码之差

    当统计左边重的情况时,有 (A+B>i+j),稍微转换一下变成 (A - i > j - B),此时出现了差的形式。对于三个统计的情况都可以这样变换。

    • 当统计左边重时,有 (A+B>i+j),转化成 (A-i>j-B)。那么只有 (A-i) 的最小值大于 (j-B) 的最大值或者 (B-i) 的最小值大于 (j - A) 的最大值才有贡献。
    • 当统计右边重时,和左边的情况相反。类比推理即可。
    • 当统计两边一样重时,(A+B = i+j),转换成 (A-i = B-j)。那么只有 (A-i) 的最小值等于 (B-j) 的最大值并且 (A-i) 的最大值等于 (B-j) 的最小值 或者 (A,B)交换后成立的时候才有贡献。

    (A,B) 匹配的 (i,j) 暴力枚举即可。

    总的复杂度是 (O(n^3))

    更多细节看代码。

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 1e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    int n, A, B;
    char s[55][55];
    int dis[55][55], Dis[55][55];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    int main()
    {
        n = read(), A = read(), B = read();
        for(int i = 1; i <= n; ++i) cin >> s[i] + 1;
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                if(s[i][j] == '=') {
                    dis[i][j] = 0, Dis[i][j] = 0; // 0 <= i - j <= 0
                } else if(s[i][j] == '+') {
                    dis[i][j] = -1, Dis[i][j] = -2; // 1 <= i - j <= 2
                } else if(s[i][j] == '-') {
                    dis[i][j] = 2, Dis[i][j] = 1; // -2 <= i - j <= -1 
                } else {
                    dis[i][j] = 2, Dis[i][j] = -2; // -2 <= i - j <= 2
                }
            }
        }
        for(int k = 1; k <= n; ++k) {
            for(int i = 1; i <= n; ++i) {
                if(i == k) continue;
                for(int j = 1; j <= n; ++j) {
                    if(k == j || i == j) continue;
                    dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); // 最短路跑最大值 
                    Dis[i][j] = max(Dis[i][j], Dis[i][k] + Dis[k][j]); // 最长路跑最小值 
                }
            }
        }
        int cnt1 = 0, cnt2 = 0, cnt3 = 0;
        for(int i = 1; i <= n; ++i) {
            if(i == A || i == B) continue;
            for(int j = 1; j < i; ++j) { // 暴力枚举 让每组砝码都选一遍 
                if(j == A || j == B) continue;
                if(Dis[i][A] > dis[B][j] || Dis[i][B] > dis[A][j] ) // A + B > i + j -> A - i > j - B
                    cnt1++;
                if((dis[i][A] == Dis[B][j] && Dis[i][A] == dis[B][j]) || (dis[i][B] == Dis[A][j] && Dis[i][B] == dis[A][j])) // A + B == i + j
                    cnt2++;
                if(Dis[A][i] > dis[j][B] || Dis[B][i] > dis[j][A] ) // A + B < i + j -> i - A > B - j
                    cnt3++;
            }  
        }
        printf("%d %d %d", cnt1, cnt2, cnt3);
        return 0;
    }
    
  • 相关阅读:
    [bbk5102] 第38集 第四章 Flashback Database 02
    index
    [bbk5110] 第41集 第四章 Flashback Database 05
    支持向量机SVM基本问题
    凸优化小结
    博客基本操作
    感知机vs支持向量机
    PAYPAL商户集成指南-IPN&PDT变量列表
    一个IBM人的离职泪:伟大公司,SB老板,苦逼员工 (zz.IS2120.BG57IV3)
    Google Reader 7.1停止服务
  • 原文地址:https://www.cnblogs.com/Silymtics/p/14864634.html
Copyright © 2011-2022 走看看