问题虫洞:J——Upgrading Technology
黑洞内窥:
有 n种科技,每种科技上限等级为 m,初始等级为0 ,
当第 i 种科技 由(j-1)级升到 j 级时,需要花费Cij 的 pokedollars(当成技能点吧!)
又当你所有的等级都达到了 j 级时, 你将获得系统奖励的技能点 dj
问,在你给科技升级的过程中,最大获得的技能点数。。
(n,m <= 1000, | Cij, dj | <= 10^9)
思维光年:
疯狂wa的做法:
算出每一行的前缀和s[ i ] [ j ] , 和每一列的和与全部升级奖励d[ j ] 的差 lie[ j ] ,
lie[ j ] 这个差值的前缀和。。
用二维线段树维护 每一行的前缀和最小值。tree[ j ][ node ]
从列开始每一列跑一遍,跑的过程中用线段树维护大于i 级可能需要增加的技能点,
最后取最大值。。。。。
(很显然,是错的,但我不知道为什么。。。)
正确的做法:
求出每一行的前缀和 s[ i ] [ j ], 以及每一行的 后缀和 p [ i ] [ j ]
然后两边维护,,,
感觉就是省了我线段树维护那一段,,,但是我wa了。。。
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
//#include <map>
//#include <set>
//#include <vector>
//#include <queue>
//#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
using namespace std;
typedef long long ll;
#define MAXN 45689
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 1000000007;
ll a[1005][1005];
ll zui[1005][1005];
int main()
{
int t, n, m, ccc=1;
cin >> t;
while(t--)
{
memset(a, 0, sizeof(a));
memset(zui, 0, sizeof(zui));
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=m; ++j)
{
scanf("%lld", &a[i][j]);
a[i][j] += a[i][j-1];
}
zui[i][m] = a[i][m];
for(int j=m-1; j>=0; --j) //求每一行后缀和(后遍历)
zui[i][j] = min(zui[i][j+1], a[i][j]);
}
ll sum=0, ans=0;
for(int j=0, c; j<=m; ++j)
{
ll mn=0, mx=0;
for(int i=1; i<=n; ++i)
{
mn+=a[i][j]; //列求和
mx+=zui[i][j];
}
for(int i=1; i<=n; ++i)
mn = min(mn, mx - zui[i][j] + a[i][j]);
sum = max(sum, ans - mn); //维护损失的值
if(j < m)
{
scanf("%d", &c); //得到dj
ans+=c;
}
}
printf("Case #%d: %lld\n", ccc++, sum);
}
return 0;
}
还有我wa到想死的代码~~~~~不太聪明的亚子,,,求dalao指教
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
//#include <map>
//#include <set>
//#include <vector>
//#include <queue>
//#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 1000000007;
ll a[1005][1005];
ll d[1005];
ll lq[1005][1005]; //每行的前缀和
ll cl[1005];
ll lie[1005]; //列求和的差
ll cha[1005]; //差值前缀和
ll tree[1005][8005];
void build(ll l, ll r, ll node, ll i)
{
if(l == r)
{
tree[i][node] = lq[i][l];
return;
}
ll mid = (l+r) >> 1;
build(l, mid, node<<1, i);
build(mid+1, r, node<<1|1, i);
tree[i][node] = min(tree[i][node<<1], tree[i][node<<1|1]);
}
ll query(ll L, ll R, ll l, ll r,ll node, ll i)
{
if(L <= l && r <= R) return tree[i][node];
ll m = (l+r)>>1, ret=1e15;
if(L <= m) ret = min(ret, query(L, R, l, m, node<<1, i));
if(R > m) ret = min(ret, query(L, R, m+1, r, node<<1|1, i));
return ret;
}
int main()
{
ll t, ccc=1;
cin >> t;
while(t--)
{
ll n, m;
scanf("%lld %lld", &n, &m);
for(ll i=0; i<=n; ++i) //置0
{
for(ll j=0; j<=m; ++j)
{
d[j] = cl[j] = lie[j] = cha[j] = 0;
a[i][j] = lq[i][j] = 0;
}
}
for(ll i=0; i<=n; ++i)
{
for(ll j=0; j<=4*m; ++j)
{
tree[i][j] = 0;
}
}
for(ll i=1; i<=n; ++i)
{
for(ll j=1; j<=m; ++j)
{
scanf("%lld", &a[i][j]);
lq[i][j] = lq[i][j-1] + a[i][j];
}
}
for(ll i=1; i<=n; ++i)
build(1, m, 1, i);
for(ll i=1; i<=m; ++i)
{
for(ll j=1; j<=n; ++j)
{
cl[i]+=a[j][i];
}
}
for(ll i=1; i<=m; ++i)
{
scanf("%lld", &d[i]);
lie[i] = d[i] - cl[i];
cha[i] = cha[i-1]+lie[i];
}
ll maxx = 0;
for(ll k=0; k<=m; ++k)
{
ll sum = cha[k];
for(ll i=1; i<=n; ++i)
{
ll ans=lq[i][k], cnt=0, tem = lq[i][k];
ll xx = query(k, m, 1, m, 1, i);
if(ans > xx)
ans = xx;
sum+=(tem - ans);
}
maxx = max(maxx, sum);
}
printf("Case #%lld: %lld\n", ccc++, maxx);
}
return 0;
}
//3 4
//1 2 7 -12
//3 5 -6 100
//2 1 0 5
//10 6 -3 10
//2 2
//1 2
//2 -1
//4 1
//3 3
//1 2 3
//1 2 3
//1 2 3
//6 7 8