cf958 C2. Encryption (medium)(dp)

题意:

把长为n的数组切成k段,每段的得分为段中的数之和模p。问总分最大是多少(总分不用模p)

n <= 2e4,k <= 50,p <= 100

思路:

先考虑朴素dp。\(f(i,k)\) 表示把第 \(1\sim i\) 个数切成 \(k\) 段的最大答案,则 \(f(i,k) = max _{j<i} \{ f(j,k-1) + s[i]-s[j] \}\),其中 \(s[]\) 为前缀和取模。复杂度 \(O(n^2k)\) ,会超时。

优化:注意到p很小,\(f(s[i],k)=max _{0\le s' < p} \{f(s',k-1) + s[i]-s' \}\)

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

for(int i = 1; i <= n; i++)
for(int ss = 0; ss < p; ss++)
for(int k = 1; k <= K; k++)
    f[s[i]][k] = max(f[s[i]][k], f[ss][k-1] + (s[i] - ss + p) % p);
    
cout << f[s[n]][K];
上一篇:第3章黑盒测试自测


下一篇:剑指 Offer 32 - I. 从上到下打印二叉树(medium) javascript解法