[题解]Yet Another Subarray Problem-DP 、思维(codeforces 1197D)

题目链接:https://codeforces.com/problemset/problem/1197/D



题意:

给你一个序列,求一个子序列 a[l]~a[r] 使得该子序列的 sum(l,r)-k*(r-l+1)/m(向上取整)的值是在所有子序列中最大的,并输出最大值

思路:

法一动态规划

dp[i][j] 表示序列到i截止,这一轮已经进行了j次取数(j = (len+m-1)%m)

那么dp[i][j]维护的就是起点为 s = i-j+1-m*t (t>=0)这个集合的最优,这样所有的 dp[i][j] 就可以维护以 i 截止的最优答案了

对于当前i更新有两种情况:

第一种是只取当前这个 a[i] 这个在 dp[i][1] 特判即可

第二种是还要取前面的,dp[i][j] 从 dp[i-1][j-1](因为 dp[i-1][j-1] 所维护的s集合和 dp[i][j] 所维护的s集合是一样的)转移即可(注意边界条件)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll inf=200000000000000;
 8
 9 int n,m;
10 ll ans=0,dp[300005][20],sum[300005],a[300005],k;
11
12 int main()
13 {
14     scanf("%d%d%lld",&n,&m,&k);
15     for(int i=1;i<=n;i++)
16     {
17         scanf("%lld",&a[i]);
18         sum[i]=sum[i-1]+a[i];
19     }
20     for(int i=1;i<=n;i++)
21     {
22         for(int j=0;j<=m;j++) dp[i][j]=-inf;
23     }
24     dp[1][1]=a[1]-k;
25     for(int i=2;i<=n;i++)
26     {
27         dp[i][1]=a[i]-k;
28         for(int j=1;j<=min(i,m);j++)
29         {
30             if(j==1) dp[i][j]=max(dp[i][j],dp[i-1][m]+a[i]-k);
31             else dp[i][j]=max(dp[i][j],dp[i-1][j-1]+a[i]);
32         }
33     }
34     for(int i=1;i<=n;i++)
35     {
36         for(int j=1;j<=m;j++) ans=max(ans,dp[i][j]);
37     }
38     cout<<ans<<endl;
39     return 0;
40 }

法二:尺取法

多加了一层维护 start_point%m=rnd,进行m次尺取法即可

(在时间够的情况下,搞不清楚当前单调队列弹出几个是最优的,那么就枚举,这样就不用担心前面要弹出什么了,只需在 len%m=0 时判断是否要把起始点重置即可)

即如果当前的和减去 k*t 小于0,那么就重新开始,否则继续加

注意 ans 在每一次向后扩展时都要更新

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=300005;
 5 ll ans=0,n,a[N],m,k;
 6
 7 int main()
 8 {
 9     scanf("%lld%lld%lld",&n,&m,&k);
10     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
11     for(int rnd=1;rnd<=m;rnd++){
12         ll len=0; ll now=0;
13         for(int i=rnd;i<=n;i++){
14             if(len%m==0) if(now-len/m*k<0) now=0,len=0;
15             now+=a[i]; len++;
16             ans=max(ans,now-(len+m-1)/m*k);
17         }
18     }
19     cout<<ans<<endl;
20     return 0;
21 }

法三:前缀和

我们可以发现 m 很小,只有10,而当子段长度能整除以 m 的时候,再添加一个才会使得我们多去减一个 k

我们可以让所有位置对 m 取模,分成 0—m-1 这样的剩余系,我们枚举剩余系,以剩余系中的位置作为结尾求最大值

当我们枚举到剩余系i的时候,我们另所有处于剩余系i的位置上的数 -k,之后我们直接扫一遍序列,不断累加并和 0 求最大值,遇到可结束位置时,与答案取最大值并更新答案

这样子我们可以再 O(nm) 的时间复杂度下做出这道题

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 3e5+5;
 5 int n,m,k,a[maxn],b[maxn];
 6
 7 int main(){
 8     cin>>n>>m>>k;
 9     for(int i=1;i<=n;i++)
10         cin>>a[i];
11     ll ans=0,s=0;
12     for(int j=0;j<m;j++){
13         for(int i=1;i<=n;i++)
14             if(i%m==j)
15                 b[i]=a[i]-k;
16             else
17                 b[i]=a[i];
18         s=0;
19         for(int i=1;i<=n;i++){
20             s=max(s+b[i],0ll);
21             if(i%m==j)
22                 ans=max(ans,s);
23         }
24     }
25     cout<<ans<<endl;
26     return 0;
27 }

参考:https://www.cnblogs.com/Forever-666/p/11241525.htmlhttp://blog.leanote.com/post/icontofig/Educational-Codeforces-Round-69

原文地址:https://www.cnblogs.com/Yanick/p/11290641.html

时间: 2024-08-01 20:49:54

[题解]Yet Another Subarray Problem-DP 、思维(codeforces 1197D)的相关文章

D. Yet Another Subarray Problem 思维 难

D. Yet Another Subarray Problem 这个题目很难,我比赛没有想出来,赛后又看了很久别人的代码才理解. 这个题目他们差不多是用一个滑动窗口同时枚举左端点和右端点,具体如下: 首先枚举0~m,这个是说更新的位置,如果是1 当m==3 就更新1 4 7 10... 如果是2,当m==3 就更新 2 6 8 11.... 最后都会被更新的. 核心代码 for (int j = 0; j < n - i; ++j) { s += sum[j]; if (j % m == 0)

Jam&#39;s math problem(思维)

Jam's math problem Submit Status Practice HDU 5615 Description Jam has a math problem. He just learned factorization.  He is trying to factorize  into the form of .  He could only solve the problem in which p,q,m,k are positive numbers.  Please help

[题解]UVA10026 Shoemaker&#39;s Problem

链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=967 描述:要做n双鞋子,第 i 双鞋子要做Ti天,每天消耗Si的钱(当前正在做第 i 双鞋子时不耗钱).求在最少消耗钱的情况下做鞋子的顺序. 思路:贪心 明显是一个排序的模型,然后我们就思考顺序怎么确定.考虑当前两双鞋子a和b,它们的顺序对它们前后的鞋子都没有影响,它们所创造的影响仅仅

dp解Codeforces Round #260 (Div. 2)C. Boredom

#include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; lo

【题解】P4137 Rmq Problem(莫队)

[题解]P4137 Rmq Problem(莫队) 其实这道题根本就不用离散化! 因为显然有\(mex\)值是\(\le 2\times 10^5\)的,所以对于大于\(2\times 10^5\)的数我们可以忽略. 然后直接莫队算就是的,开一个\(2e5\)的桶 若一个比答案小的值的桶为\(0\)了:答案更新为它 若这个\(mex\)的桶突然有值了:暴力枚举答案变大,第一个桶里没值的就是答案,更新. 有小伙伴会问,这复杂度不上天了?其实不然.移动\(ans\)的总复杂度(好像)是\(O(n\s

Codeforces Gym 100342D Problem D. Dinner Problem Dp+高精度

Problem D. Dinner ProblemTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/attachments Description A group of k students from Cooking University living in the campus decided that each day of the semester one of them will p

codeforces 706C Hard problem DP(动态规划)问题

题目链接:http://codeforces.com/problemset/problem/706/C 题目大意:  给定n个字符串, 每个字符串可以颠倒前后位置(第一个字母到最后一个,第二个字母到倒数第二位) 每次颠倒需要花费ci的力气, 要求将所给的n个字符串用最小力气按字典序排列, 输出力气值, 如果无法按字典序排列, 则输出-1 数据范围:2?≤?n?≤?100?000 . ci (0?≤?ci?≤?1e9) 所有字符串总长度不会超过1000000. 解题思路: 这是一道DP题, dp[

Codeforces 706 C. Hard problem (dp)

题目链接:http://codeforces.com/problemset/problem/706/C 给你n个字符串,可以反转任意一个字符串,反转每个字符串都有其对应的花费ci. 经过操作后是否能满足字符串str[i]>=str[i-1],能就输出最小花费,不能输出-1. dp[i][0] 表示不反转i的最小花费(str[i] >= str[i - 1] || str[i] >= reverse(str[i - 1])) dp[i][1] 则表示反转i的最小花费... 初始dp[1][

Educational Codeforces Round 26 D dp,思维

Educational Codeforces Round 26 D. Round Subset 题意:有 n 个数,从中选出 k 个数,要使这 k 个数的乘积末尾的 0 的数量最多. tags:dp好题 dp[i][j][l] 表示前 i 个数,选取了其中 j 个数,分解因子后有 l 个 5时,最多有多少个 2 .i 这一维明显可以省略. 这题一开始有个地方写挫了..选取 j 个数时,应该反着来,即 for( j, k, 1) ,不是 for( j, 1, k) ,不然会多算. #include