2019牛客暑期多校训练营(第六场)J Upgrading Technology(矩阵前缀和+最小子串和+贪心)

题目链接:https://ac.nowcoder.com/acm/contest/886/J

题目大意:

  有n个种类的树,每个种类对应m个级别。每个种类升级都需要一定的成本,且当n个种类的等级都达到一个等级时,将获得这个等级的利润,问能获得的最大金额。

解题报告:

  学到了新的东西:最小子串和,可以记录从i点开始往后的最小自串和。

  题解都在代码里,根据当前的矩阵前缀和,和找n-1条子串的最小子串和(因为是成本所以要最小,至多n-1条边,否则就构成矩阵了,没必要重复判断)。

AC代码:

 1 #include<bits/stdc++.h>
 2 #define numm ch-48
 3 #define pd putchar(' ')
 4 #define pn putchar('\n')
 5 #define pb push_back
 6 #define fi first
 7 #define se second
 8 #define fre1 freopen("1.txt","r",stdin)
 9 #define fre2 freopen("2.txt","w",stdout)
10 using namespace std;
11 template <typename T>
12 void read(T &res) {
13     bool flag=false;char ch;
14     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
15     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
16     flag&&(res=-res);
17 }
18 template <typename T>
19 void write(T x) {
20     if(x<0) putchar('-'),x=-x;
21     if(x>9) write(x/10);
22     putchar(x%10+'0');
23 }
24 
25 typedef long long ll;
26 const int maxn=1010;
27 const int N=60;
28 const int inf=0x3f3f3f3f;
29 const ll INF=0x3f3f3f3f3f3f3f3f;
30 const int mod=998244353;
31 
32 ll mp[maxn][maxn];  ///每行每列的元素
33 ll d[maxn];         ///每列的利润
34 ll wtz[maxn];       ///记录从1到i列的矩阵前缀和
35 ll dp[maxn][maxn];  ///记录最小子串和
36 ll ls[maxn];        ///利润前缀和
37 int main()
38 {
39     int _,k=0,n,m;
40     read(_);
41     while(_--) {
42         read(n),read(m);
43         for(int i=1;i<=n;i++)
44             wtz[i]=0;
45         for(int i=1;i<=n;i++)
46             for(int j=1;j<=m;j++) {
47                 read(mp[i][j]);
48                 wtz[j]+=mp[i][j];
49             }
50         for(int i=1;i<=m;i++)       ///从1到i列的矩阵前缀和
51             wtz[i]+=wtz[i-1];
52         for(int i=1;i<=n;i++) {         ///记录最小子串和
53             dp[i][m+1]=0;
54             for(int j=m;j>=1;j--)
55                 dp[i][j]=min(dp[i][j+1]+mp[i][j],mp[i][j]);
56         }
57         for(int i=1;i<=n;i++)
58             for(int j=1;j<=m;j++)
59                 if(dp[i][j]>0)
60                     dp[i][j]=0;
61         for(int i=1;i<=m;i++) {
62             read(d[i]);
63             ls[i]=ls[i-1]+d[i];
64         }
65         ll res=0;
66         for(int i=1;i<=m;i++) {
67             ll sum=0,del=-INF;
68             for(int j=1;j<=n;j++) {
69                 del=max(dp[j][i],del);       ///要减掉的那一行
70                 sum+=dp[j][i];
71             }
72             res=max(ls[i-1]-(sum-del)-wtz[i-1],res);    ///利润-子串和(至多n-1个)+矩阵前缀和
73         }
74         res=max(ls[m]-wtz[m],res);
75         printf("Case #%d: ",++k);
76         write(res);pn;
77     }
78     return 0;
79 }
代码在这里!

猜你喜欢

转载自www.cnblogs.com/wuliking/p/11296573.html