牛场围栏
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;
}