アップグレードテクノロジ
問題解決のためのアイデア
この問題のために、私たちは現在の最小レベルをk、kは上昇し、少なくとも1つのレベルがある表し、すべてのスキルを入れて、0〜Mからk個を列挙することができます。
この時点で、私たちは最初のk dを[]の利益を獲得し、そしてそれはレベルkに上昇するのにかかるすべてのスキルを過ごしました。今、我々は(現在の状況下で最大の利益を得るために、我々は、このスキルを通じて最大の利益を得ることができるように、一定のレベルにそれぞれのスキルをアップグレードし続ける必要があり、kに上昇する、すなわち最小コストを、すべてのスキルを持っているので、 )、即ち、S [K〜M]最小 - S [k]は(S [])このスキルおよび費用の接頭辞です。私たちは、この最小値を維持するために、単調なキューを使用することができます。しかし、我々は、我々は所得の列挙を満たしていない現時点では、すべてのスキルが最大と利益を上げることができ、すべてのスキルレベルがk個以上のものになります問題は、ただ最初のk dを[]のを取得しています「条件が、私たちは最大のコストの1を追加する必要があり、少なくとも一つのスキルレベルは正確にkに等しく、かつ最小の損失です。
最終的な答えは、列挙の場合には最大です。
コードは以下の通りです
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read(){
int res = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
res = (res << 3) + (res << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -res : res;
}
const int N = 1005;
ll c[N][N], s[N][N];
ll d[N];
int main()
{
int _ = read();
for(int u = 1; u <= _; u ++){
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++)
scanf("%lld", &c[i][j]);
}
for(int j = 1; j <= m; j ++)
scanf("%lld", &d[j]);
ll t[N];
t[0] = 0;
for(int j = 1; j <= m; j ++){
ll w = 0;
for(int i = 1; i <= n; i ++)
w += c[i][j];
t[j] = d[j] - w + t[j - 1];
}
deque<int> dq[N];
for(int i = 1; i <= n; i ++){
for(int j = 0; j <= m; j ++){
s[i][j] = s[i][j - 1] + c[i][j];
while(!dq[i].empty() && s[i][dq[i].back()] >= s[i][j])
dq[i].pop_back();
dq[i].push_back(j);
}
}
ll ans = 0;
for(int j = 0; j <= m; j ++){
ll temp = t[j];
ll mx = -2223372036854775808LL;
for(int i = 1; i <= n; i ++){
while(!dq[i].empty() && dq[i].front() < j)
dq[i].pop_front();
int top = dq[i].front();
ll r = s[i][top] - s[i][j];
mx = max(mx, r);
temp -= r;
}
temp += mx;
ans = max(ans, temp);
}
printf("Case #%d: %lld\n", u, ans);
}
return 0;
}