牛场围栏

prologue

建议大家特别关注自己新建完长度那个数组,我用错然后调了 20min。(代码 5min,调试 20min 的屑。(

analysis

观察题目,抛去所有条件,发现本质是让我们用一堆数字去拼凑数字,然后找到最大的一个拼凑不成的数字。很符合同余最短路的模板样子,所以我们就开始往同余最短路这一方面考虑。

这个时候审题发现,题目中说每跟木棒是可以磨去最多 \(m\) 的,我们就可以把所有木棒给提前预处理出来。

对于同余最短路,众所不周知,有两种做法,一种就是顾名思义,用最短路进行解决,另一种我们可以用一种神奇的转圈方法去解决。如果还不会请自行左转或者右转到大佬的博客进行学习。

code time

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
#define rl register ll

const ll N = 1e7 + 10, M = 110;

ll n, m,l[M], tot, a[N], f[N];

ll ans = -1;

inline void add()
{
    for(rl i=1; i <= n; ++ i)
        for(rl j=0; j <= m; ++ j)
        {
            ll x = l[i] - j;
            if(x <= 0) break;
            a[ ++ tot] = x;
        }
}

inline ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}   

int main()
{
    // freopen("1.in", "r", stdin), freopen("1.out", "w", stdout);

    cin >> n >> m;

    for(rl i=1; i <= n; ++ i) cin >> l[i];

    add();

    sort(a + 1, a + 1 + tot);
    
    m = a[1];

    memset(f, 0x3f, sizeof f); f[0] = 0;

    for(rl i=2; i <= tot; ++ i) // 没错啊,就是这个这里,不要写成 n !!!是tot!!!因为你分割了!!!
        for(rl j=0, lim = __gcd(m, a[i]); j < lim; ++ j) 
            for(rl t=j, c = 0; c < 2; c += t == j)
            {
                ll p = (t + a[i]) % m;
                f[p] = min(f[p], f[t] + a[i]), t = p;
            }
    
    for(rl i=0; i < a[1]; ++ i)
        ans = max(ans, f[i] - m);
    

    cout << ans << endl;
    return 0;
}
posted @ 2023-10-06 14:59  carp_oier  阅读(12)  评论(0编辑  收藏  举报