题解:P8794 [蓝桥杯 2022 国 A] 环境治理

道路改善天数增长,“出行环境”的值并不会减少,具有单调性,考虑二分最少天数。

看见 \(P=\sum \limits_{i=0}^{n-1} \sum \limits_{j=0}^{n-1} d(i,j)\),是多源最短路,又 \(n \le 100\),尝试 Floyd。

重点在二分的检查函数。定义一个函数(暂时叫 ql),用于计算一个点被清理的次数。清理 \(x\) 天,将其分为 \(x \div n\)\(N\)\(x \bmod n\)\(1\),每个点都会被清理至少 \(x \div N\) 次(它是依次清理的,分配完 \(x \div n\)\(N\)),剩余 \(x \bmod n\)\(1\) 则将分配到点 \(1 \sim (x \bmod n)\)。这 \(x \bmod n\) 个点清理次数就会比其他店多清理 \(1\) 次。

很显然,此时每条边的“灰尘度”为 max(L[i][j] ,D[i][j] - ql(i) - ql(j)

再跑一遍 Floyd,计算每条最短路径的“灰尘度”,累加起来,如果 \(\le Q\),就返回真,否则返回假。

奉上代码:

# include <bits/stdc++.h>
# define ql(num) (x / n + (num <= x % n))
using namespace std;
int n , q , d[110][110] , l[110][110] , dp[110][110];
bool check(int x)
{
    int sum = 0;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            dp[i][j] = max(l[i][j] , d[i][j] - ql(i) - ql(j));
    for(int k = 1 ; k <= n ; k ++)
        for(int i = 1 ; i <= n ; i ++)
            for(int j = 1 ; j <= n ; j ++)
                dp[i][j] = min(dp[i][j] , dp[i][k] + dp[k][j]);
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            sum += dp[i][j];
    if(sum <= q) return 1;
    return 0;
}
int main()
{
    cin >> n >> q;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            cin >> d[i][j];
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            cin >> l[i][j];
    int l = 0 , r = 0x3f3f3f3f;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    if(check(l)) cout << l;
    else cout << -1;
    return 0;
}

如果你看到这儿,就说明你已经看了我的代码,面向题解编程需要注意以下几点:

  • 我直接用 define 弄得函数,如果要写函数还要把清理天数 \(x\) 设为全局变量或传进去。

  • 请注意左边界一定要为 \(0\),最开始就可能已经满足条件。

  • 请注意像我这样写二分最后要检查一遍,因为有无法满足条件的情况。

  • 跑 Floyd 与求和要分开!我因为这个卡了好久。

题外话:话说怎么 1.82k 通过却只有两篇题解

posted @ 2025-08-18 12:50  zhangyimin12345  阅读(15)  评论(0)    收藏  举报