第一行 n (1 <= n <= 105), k (0 <= k <= 105) ,表示这堂课持续多少分钟,以及叫醒小易一次使他能够保持清醒的时间。
第二行 n 个数,a1, a2, ... , an(1 <= ai <= 104) 表示小易对每分钟知识点的感兴趣评分。
第三行 n 个数,t1, t2, ... , tn 表示每分钟小易是否清醒, 1表示清醒。
小易这堂课听到的知识点的最大兴趣值。
6 3 1 3 5 2 5 4 1 1 0 1 0 0
16
主要思想是将知识点分值化为两部分来分别计算,一部分为保持清醒的时段,此时段的知识点分值固定不受叫醒时间影响;另一部分为根据叫醒时间额外增加的分值,遍历所有可能被叫醒的点,并计算出从该点开始后k个点内新增的知识点分,比较各个可叫醒点的该值取最大。需注意的是在求取可叫醒点i的新增知识点分时,若直接再使用循环遍历后面k个点复杂度较高,此处使用一个睡眠点分值的累加数组来进行优化。
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int k = scan.nextInt();
int[] val = new int[n];
int[] state = new int[n];
//保存瞌睡时的累计评分
int sleep = 0;
int[] sleepval = new int[n];
for(int i=0;i<n;i++){
val[i] = scan.nextInt();
}
for(int i=0;i<n;i++){
state[i] = scan.nextInt();
if(state[i]==0){
sleep += val[i];
}
sleepval[i] = sleep;
}
Main ma = new Main();
int res = ma.getMaxVal(val,state,n,k,sleepval);
System.out.println(res);
}
public int getMaxVal(int[] val,int[] state,int n,int k,int[] sleepval){
int res = 0;
int addval = 0;
for(int i=0;i<n;i++){
if(state[i]==1) res += val[i];
else{
int wakeval = 0;
if(i+k-1>=n){
wakeval =(i>0)?(sleepval[n-1]-sleepval[i-1]):sleepval[n-1];
}else{
wakeval = (i>0)?(sleepval[i+k-1]-sleepval[i-1]):sleepval[i+k-1];
}
addval = addval>=wakeval?addval:wakeval;
}
}
return res+addval;
}
}
"""
思路:从左到右遍历,比较k长度内睡着0状态对应兴趣值的和,即叫醒一下提升的兴趣值。
总值分为两部分:醒着的固定值 + 睡着的提升值的最大值
"""
n,k =list(map(int, input().split()))
values =list(map(int, input().split()))
awakes =list(map(int, input().split()))
#n,k = [6,3]
#values = [1, 3, 5, 2, 5, 4]
#awakes = [1, 1, 0, 1, 0, 0]
base_score =0
for i in range(n):
if awakes[i]:
base_score += values[i]
values[i] =0
max_boost_score =0
for i in range(n):
if not awakes[i]:
boost_score =sum(values[i:min(i+k,n)])
max_boost_score =max(boost_score,max_boost_score)
# 加了下面的break语句,才使这个代码时间上终于达标
# 扫描到距结尾不足k距离范围内的第一个睡着状态即可,后面的肯定不如这个的提升值大,没必要再跑,可提前结束
ifi > n-k+1:
break
score =base_score +max_boost_score
print(score)
#include <iostream>
#include <vector>
using namespace std;
// 连续k个中0对应的最大和, 才是叫醒额外获取的时间
int process(const vector<int> & interest, const vector<int> & aweak, int k) {
int max_scores = 0;
int scores = 0;
// 叫醒k分钟
k = min(k, (int)interest.size()); // 最多能清醒这么长
// 先计算前k个的零和
for (int i = 0; i < k; ++i) {
if (0 == aweak[i]) {
scores += interest[i];
}
}
// 将k数组往后移动
max_scores = scores;
for (int i = k; i < interest.size(); ++i) {
if (0 == aweak[i]) {
scores += interest[i];
}
if (0 == aweak[i - k]) {
scores -= interest[i - k];
}
max_scores = max(max_scores, scores);
}
return max_scores;
}
int main() {
int n = 0; // 共几分钟
int k = 0; // 叫醒能清醒K分钟
while (cin >> n >> k) {
vector<int> interest(n);
vector<int> aweak(n);
int scores = 0;
for (int i = 0; i < n; ++i) {
cin >> interest[i];
}
for (int i = 0; i < n; ++i) {
cin >> aweak[i]; // is aweak?
}
// 叫醒k分钟
scores = process(interest, aweak, k);
for (int i = 0; i < n; ++i) {
scores += interest[i] * aweak[i];
}
cout << scores << endl;
}
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int cLength = sc.nextInt();//这节课的时长:分钟数
int lLength = sc.nextInt();//提醒一次能清醒的分钟数
int [] sumAll = new int[cLength + 1];//表示每分钟所有兴趣点相加
int [] sumBefore = new int[cLength + 1];//表示有效(醒着)的兴趣值相加
int maxInterst = 0;//叫醒后产生的最大听课效益
int sub;//表示 叫醒后lLength分钟的兴趣点 - 之前 llength分钟xing'qu'dia
int[] intrests = new int[cLength];
int[] isSleep = new int[cLength];
for (int i = 0; i < cLength; i++) {
intrests[i] = sc.nextInt();
sumAll[i + 1] += intrests[i] + sumAll[i];
}
for (int k = 0; k < cLength; k++) {
isSleep[k] = sc.nextInt();
if (isSleep[k] == 1)
sumBefore[k+1] += sumBefore[k] + intrests[k];
else
sumBefore[k+1] =sumBefore[k];
}
/*以上为输入环节*/
//边界条件
if(lLength >= cLength) {
System.out.println(sumAll[cLength]);
return;
}
if(lLength < 1){
System.out.println( sumBefore[cLength]);
return;
}
// 1<= llength <clength
for (int i = 0 ;i < cLength; i++){
// 提醒后 清醒的时间段 在上课时间内,就是提醒效果在上课时间内有效
if (i + lLength -1 < cLength && isSleep[i] == 0){
sub = (sumAll[i +lLength] - sumAll[i]) - (sumBefore[i +lLength] - sumBefore[i]);
if(sub > maxInterst)
maxInterst = sub;
//提醒效果还有,但是已经下课了。
}else if (i + lLength -1 >= cLength && isSleep[i] == 0){
sub = (sumAll[cLength] - sumAll[i]) - (sumBefore[cLength] - sumBefore[i]);
if(sub > maxInterst)
maxInterst = sub;
}
}
System.out.println(maxInterst + sumBefore[cLength]);
}
}
JavaScript 100%通过
let line1 = readline().split(' '),
line2 = readline().split(' ').map(Number),
line3 = readline().split(' '),
n = parseInt(line1[0]),
k = parseInt(line1[1]);
let count = 0,
maxZeroCount = 0,
ZeroCount = 0,
left=0,
right=0;
line3.forEach( (ele,index)=> {
if(ele == 1){
count += line2[index];
}else{
let edge = index + k;
if(edge > n ) {edge = n};
// 第一次计算,以及当left==right相等时计算,
// 因为此时k长度内只有一个‘瞌睡’,下一阶段需要重新计算。
if(left == right){
left = index;
ZeroCount=0;
for(let i=left;i< edge;i++){
if(line3[i] == 0){
ZeroCount += line2[i];
right = i;
}
}
}else{
// 当left!=right时,表明在k长度内,至少有两个‘瞌睡’,多出的‘瞌睡’
// 必然会被下一个k长度计算,所以,可以借此获得两个相邻k长度的交叉范围的值。
// 因此,计算下一个k长度时,只需计算余下部分,节省了运算时间。
ZeroCount -=line2[left];
left = index;
for(let i=right+1;i< edge;i++){
if(line3[i] == 0){
ZeroCount += line2[i];
right = i;
}
}
}
maxZeroCount = Math.max(maxZeroCount,ZeroCount);
}
});
console.log(maxZeroCount + count);
"""
base_score 为清醒时对兴趣度a的求和
max_score 为叫醒一次,k时间内最大的兴趣度
"""
import sys
if __name__ == "__main__":
# sys.stdin = open('input.txt', 'r')
n, k = list(map(int, input().strip().split()))
a = list(map(int, input().strip().split()))
t = list(map(int, input().strip().split()))
base_score = 0
for i in range(n):
if t[i]:
base_score += a[i]
a[i] = 0
max_score = tmp = sum(a[:k])
for i in range(k, n):
tmp = tmp + a[i] - a[i - k]
max_score = max(max_score, tmp)
ans = base_score + max_score
print(ans)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] interset = new int[n];
int[] isAwake = new int[n];
int[] sumInterestOf0 = new int[n];
for (int i = 0; i < n; i++) {
interset[i] = sc.nextInt();
}
int sum0 = 0;
int sum1 = 0;
for (int i = 0; i < n; i++) {
isAwake[i] = sc.nextInt();
if (isAwake[i] == 1) {
sum1 += interset[i];
} else {
sum0 += interset[i];
}
sumInterestOf0[i] = sum0;
}
int cur = 0;
int max = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
if (isAwake[i] == 0) {
if (i + k - 1 > n - 1) {
cur = sumInterestOf0[n - 1] - (i - 1 >= 0 ? sumInterestOf0[i - 1] : 0);
} else {
cur = sumInterestOf0[i + k - 1] - (i - 1 >= 0 ? sumInterestOf0[i - 1] : 0);
}
max = cur > max ? cur : max;
}
}
System.out.println(sum1 + max);
}
}
#include<iostream>
#include<vector>
#include<algorithm>
//总分数分为两部分:已经是清醒的分数 + 睡着的那部分如果清醒时带来的最大分数
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
int temp;
vector<int >score(n,0);
vector<int >awake(n,0);
for(int i=0;i<n;i++)
{
cin>>temp;
score[i]=temp;
}
for(int i=0;i<n;i++)
{
cin>>temp;
awake[i]=temp;
}
long sum=0,maxSum=0,baseSum = 0;
//计算基本分数
for(int i=0;i<n;i++)
{
if(awake[i])
{
baseSum+=score[i];
score[i]=0;//把清醒取得的分数置0
}
}
//若k大于等于n,则全部分数相加即可
if(k>=n)
{
for(int i=0;i<n;i++)
{
maxSum+=score[i];
}
}
//否则,滑动窗口,请窗口分数最大值
else
{
for(int j=1;j<n-k+1;j++)
{
sum = 0;
for(int kk=j;kk<j+k;kk++)
{
sum+=score[kk];
}
if(maxSum<sum)
maxSum = sum;
}
}
//输出两部分分数总和
cout<<maxSum+baseSum;
return 0;
}
import java.util.Scanner;
public class aaa {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n;
int k;
while (s.hasNext()) {
n = s.nextInt();
k = s.nextInt();
int max = 0;//被重新叫醒后可得的最高分。
int sum = 0;//表示总的分数
int[] a = new int[n];
int[] t = new int[n];
for (int i = 0; i < n; i++) {
a[i] = s.nextInt();
}
int now = 0;
for (int i = 0; i < n; i++) {
t[i] = s.nextInt();
now += t[i] * a[i];
}
int res = now;
for (int i = 0; i < n; ) {
if (t[i] == 0) {
now += 1 * a[i];
}
if (++i >= k) {
res = Math.max(res, now);
if (i-k<n&&i-k>=0) {
if (t[i-k] == 0) {
now -= 1 * a[i-k];
}
}
}
}
System.out.println(res);
}
}
}
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cin>>n>>k;
int a[n],b[n],s=0;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
cin>>b[i];
if(b[i])
s += a[i];
}
int Max = 0;
for(int i=0;i<=n-k;i++){
int t = 0;
for(int j=0;j<k;j++)
if(b[i+j]==0)
t += a[i+j];
Max = max(Max, t);
}
cout<<s+Max<<endl;
return 0;
} # 超简单答案,复杂度为O(n),By Dante nk = list(map(int,input().split())) n = nk[0] k = nk[1] a = list(map(int,input().split())) t = list(map(int,input().split())) max = 0 #记录前k个瞌睡叫醒后兴趣的最大值 for i in range(k): if(t[i]==0): max += a[i] pos = 0 #记录最大值的位置 pre = 0 #记录窗口移动过程中最后一个元素位置 cur = max #当前窗口内的兴趣值 for i in range(k,n): if(t[pre]==0): #元素过期 cur -= a[pre] if(t[i]==0): cur += a[i] pre += 1 if(cur>max): max=cur pos=i sum=0 #记录清醒状态下的和 for i in range(n): if(t[i]==1): sum+=a[i] print(sum+max)
/*
总分值=原本醒得的分值+叫醒他额外得到的分值。
额外得到的分值:单纯的遍历会超时。
这里用了一个队列的思想,进一个,出一个。
*/
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int[] fun = new int[n];
int[] sleep = new int[n];
int ans = 0;
for (int i = 0; i < n; i++) {
fun[i] = in.nextInt();
}
for (int i = 0; i < n; i++) {
sleep[i] = in.nextInt();
if (sleep[i] == 1) {
ans += fun[i];
}
}
int cnt = 0; //醒来得到的兴趣值。
for (int i = 0; i < n && i < k; i++) {
if (sleep[i] == 0)
cnt += fun[i];
}
int max = cnt;
for (int i = 1; i < n; i++) {
if (sleep[i - 1] == 0) cnt -= fun[i - 1];
if (i + k - 1 < n && sleep[i + k - 1] == 0)
cnt += fun[i + k - 1];
max = Math.max(max, cnt);
}
ans += max;
System.out.println(ans);
}
}
很简单,用两个前缀和数组配合一下就可以了。是知识点数组
的前缀和,
是知识点数组在考虑小易是否清醒时的前缀和。
if __name__ == "__main__": n, k = map(int, input().split()) a = list(map(int, input().split())) t = list(map(int, input().split())) p1, p2 = [0] * n, [0] * n # 不考虑、考虑t状态的前缀和 p1[0] = a[0] p2[0] = a[0] if t[0] else 0 for i in range(1, n): p1[i] = p1[i - 1] + a[i] p2[i] = p2[i - 1] + a[i] if t[i] else p2[i - 1] if k == 0&nbs***bsp;sum(t) == n: print(p2[-1]) # 叫不醒或者没有睡觉的时候就直接返回 else: ans = 0 for i in range(n): if t[i] == 0: if i == 0: ans = max(ans, p1[k - 1] + p2[-1] - p2[k - 1]) else: if i + k - 1 < n: ans = max(ans, p2[i - 1] + (p1[i + k - 1] - p1[i - 1]) + p2[n - 1] - p2[i + k - 1]) else: ans = max(ans, p2[i - 1] + p1[-1] - p1[i - 1]) print(ans)
//对于清醒时刻不需要处理,只处理睡着的时候(wake为0),每次计算在这一分钟前和
//连续k分钟内、以及i+k分钟以后的清醒时刻的分数
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int hobby[N],wake[N],sum[N],sum1[N];//sum[i]表示前i项和,sum1[i]表示前i项所有清醒时的分数和
int main(){
int n,k,ans = 0,tmp=0;
cin>>n>>k;
for(int i = 1;i<=n;i++){
cin>>hobby[i];
sum[i] = sum[i-1]+hobby[i];//求前n项和
}
for(int i = 1;i<=n;i++){//这个循环求前i项清醒时的分数和
cin>>wake[i];
if(wake[i]==1)
sum1[i] = sum1[i-1]+hobby[i];
else
sum1[i] = sum1[i-1];
}
for(int i = 1;i<=n;i++){
if(wake[i]==0){
if(i+k-1<=n){
tmp += sum[i+k-1]-sum[i-1];//对于所有睡着的时候,即wake[i]等于0的时候开始计算,k分钟以内的和
tmp += sum1[i];//再加上在第i分钟之前所有的清醒分数
tmp += sum1[n]-sum1[i+k-1];//再加上从i+k之后的所有清醒和
}else{
tmp += sum1[i];
tmp += sum[n]-sum[i-1];
}
ans = max(ans,tmp);//更新ans值
tmp = 0;
}
}
ans = max(tmp,ans);
cout<<ans<<endl;
return 0;
}
//滑动窗口解法,遍历一次
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
vector<int> points(n);
vector<int> weak(n);
//deque<int> window;//滑动窗口,使用双端队列,前后都可以pop和push
int sum=0;
for(int i=0;i<n;i++) cin>>points[i];
for(int i=0;i<n;i++)
{
cin>>weak[i];
if(weak[i]) sum+=points[i];//先把清醒状态的评分记录下来
}
//判断异常情况
if(k<=0)
{
cout<<sum<<endl;
return 0;
}
//初始化滑动窗口
int maxofk=0;//k个数的最大和
int curofk=0;//当前k个数的和
for(int i=0;i<k;i++)
{
//window.push_back(points[i]);
if(weak[i]==0)curofk+=points[i];
maxofk=max(maxofk,curofk);
}
int index=k;//index指向滑动窗口的右端的下一位,即将要被加入进来的数
while(index<n)//开始滑动
{
if(weak[index-k]==0)//滑动窗口的左端,将要被抛弃
curofk-=points[index-k];//window.front();
// window.pop_front();//左端弹出
if(weak[index]==0)//滑动窗口右端的下一位
curofk+=points[index];
//window.push_back(points[index]);//右端插入
maxofk=max(maxofk,curofk);//记录滑动窗口种weak[i]=0的最大和
index++;
}
cout<<sum+maxofk<<endl;
return 0;
}
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int k=sc.nextInt();
int[] a=new int[n];
int[] t=new int[n];
int[] sum=new int[2*n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
for(int i=0;i<n;i++){
t[i]=sc.nextInt();
}
for(int i=0;i+k<=n;i++){
int b[]=new int[n];
for(int j=i;j<i+k;j++){
if(t[j]==0){
b[j]=1;//记录原先修改前的a[j]的位置;
t[j]=1;
}
}
for(int j=0;j<n;j++){
sum[i]+=a[j]*t[j];
if(b[j]==1){
t[j]=0;//改回原来的数据;
}
}
}
Arrays.sort(sum);
System.out.print(sum[sum.length-1]);
}
} // 用双端队列来记录窗口内最大值,该题应该是判断在k的窗口内睡觉时间的累加和最大值是多少
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, k;
cin >> n >> k;
vector<int> score(n);
vector<int> awake(n);
for(int i=0; i<n; i++){
cin >> score[i];
}
for(int i=0; i<n; i++){
cin >> awake[i];
}
int sum = 0; //记录本来就有的分数
for(int i=0; i<n; i++){
if(awake[i] == 1){
sum += score[i];
}
}
int windowK = 0, maxNeed = 0; //windowK 记录窗口内awake[i]是0时的score和,maxNeed全局
deque<int> qmax;
for(int i=0; i<n; i++){
if(awake[i] == 0){
qmax.push_back(i);
windowK += score[i];
}
if(i-qmax.front() == k){ //只把awake是0时的分数加进去
windowK -= score[qmax.front()];
qmax.pop_front();
}
if(i >= k-1 && !qmax.empty()){ //维持窗口大小为k
maxNeed = max(maxNeed, windowK);
}
}
maxNeed += sum;
cout << maxNeed;
return 0;
} import java.util.Scanner;
public class Main {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] interest = new int[n];
for (int i = 0; i < n; i++) {
interest[i] = sc.nextInt();
}
int[] sleep = new int[n];
for (int i = 0; i < n; i++) {
sleep[i] = sc.nextInt();
}
sc.close();
//醒着的兴趣值
int AweakInterest = 0;
k = Math.min(k, n);
for (int i = 0; i < n; i++) {
AweakInterest += sleep[i] == 1 ? interest[i] : 0;
}
//遍历查每次叫醒得到最大的睡着的兴趣值
int sleepInterest = 0;
for (int i = k - 1; i < n; i++) {
int sleepInt = 0;
for (int j = i; j >= i - k + 1; j--) {
sleepInt += sleep[j] == 0 ? interest[j] : 0;
}
sleepInterest = Math.max(sleepInt, sleepInterest);
}
System.out.println(AweakInterest + sleepInterest);
}
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int k=sc.nextInt();
int[] a=new int[n];
int[] t=new int[n];
//考虑睡着不睡着的阶段和
int[] sum=new int[n];
//全部都当作不睡着的阶段和
int[] sum_all=new int[n];
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
}
for(int i=0;i<n;i++){
t[i]=sc.nextInt();
}
sum[0]=t[0]==1?a[0]:0;
sum_all[0]=a[0];
//提前算出阶段和
for(int i=1;i<n;i++){
sum_all[i]=a[i]+sum_all[i-1];
if(t[i]==1){
sum[i]=a[i]+sum[i-1];
}else {
sum[i] = sum[i - 1];
}
}
if(k>=n){
System.out.println(sum_all[n-1]);
return;
}
int max=0;
for(int i=0;i<n;i++){
if(t[i]==0){
int res=0;
int r=Math.min(n-1,i+k-1);
if(i==0){
res+=sum_all[r];
}else{
res+=(sum[i-1]+sum_all[r]-sum_all[i-1]);
}
if(i+k-1<n-1){
res+=(sum[n-1]-sum[i+k-1]);
}
max=Math.max(max,res);
}
}
System.out.println(max>0?max:sum_all[n-1]);
}
}
/*
在输入的时候先把ti=1的ai加和得到小易清醒的收益,然后再考虑ti=0的收益
为了避免在讨论ti=0的情况时还要考虑ti=1的情况,可以在输入时如下处理:
若ti=1 则累加sum+=ai
若ti=0 则构造链表 将ti=0的ai往链表尾部add node
之后只需直接对链表操作即可
(也可以选择构造数组)
初步思想是遍历:
对于链表的第i个元素bi 考虑b(i)+b(i+1)+...+b(i+k-1)总共k个时间单位所对应元素和
将i从第一个元素遍历到链表的最后一个
找出上述k个时间单位对应元素和的最大值max
将max+sum即可得到答案
易知 复杂度达到O(n^2) 对于10^5容易超时
优化方案:
(以下的区间长度指代该区间所覆盖的时间长度 不是元素个数)
本次k个时间单位对应元素和 利用上一次运算得到的k个时间单位对应元素和
我们视k个时间单位为一个区间
易知 每一次运算把上一次运算的区间的左端点向右移动一个元素
右端点并不一定向右移动一个元素 这里比较特殊 若左端点的时间单位是t 则只要时间单位
在区间[t,t+k-1]中的元素都应该被划入该区间中 因此右端点的移动距离是不确定的 需要一个个判断
这里的优化在于 可能在某一次右端点的移动距离会很长(不妨假设这次的移动距离上界为O(n))
则下次就势必会缩短 而且渐进意义上和上一次的右端点移动距离成反比 可以这么理解:
每一次区间移动的过程中 右端点或者继续向右移或者原地不动 如果这次右端点移动的距离是k-2或k-1
等非常接近k的某个值 则下一次右端点移动距离就只有0个或1个或2个或3个(否则会使得区间长度大于k)
故可以实现将O(n^2)的复杂度大幅降低接近O(n)的效果
考虑一种特例:数据大小恰好是10^5 k=10^5 且每个元素对应的ti=0
如果用初步思想遍历 显然会超时 时间复杂度:O((N^2)/2)
但如果采用优化方案 时间复杂度会优化到 O(2*N)
对于其他一般数据来说 同上述 一般只会有少数次的运算会使得右端点移动长度特别长 其余都会大幅减少
故实现优化
注意:
1. 本题最后一个样例是坑 题目已经给定条件k>=1 但最后一个样例的k=0
2. 其实本题的时间复杂度主要消耗在区间右端点的移动上 优化方案目的就是减少右端点
的移动 同时又能实现加和
3. 优化方案中的加和就是:区间和先将区间移动之前的左端点的值减掉 再根据数据将区间右端点右移
区间和加上新加入的元素 即可得到本轮的区间和 然后区间和与max比较 更新max
4. 注意区别k个时间单位所对应的元素 与 k个元素 的区别
*/
Ans:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define New(a ,i) (a*)malloc(sizeof(a)*i)
#define Cle(a) memset(a ,0 ,sizeof(a))
#define Inv -1
#define MAX 100000
typedef struct node
{
int num;
int key;
struct node* next;
}node;
node *header=NULL ,*cur=NULL ,*low=NULL ,*high=NULL;
int n=0 ,k=0;
int a[MAX];
int t;
int sum=0 ,max=Inv;
void initial()
{
header=New(node ,1);
header->num=header->key=Inv;
header->next=NULL;
cur=low=high=header;
}
void add(int ti ,int key)
{
node* temp=New(node ,1);
temp->num=ti;
temp->key=key;
temp->next=NULL;
cur->next=temp;
cur=temp;
}
void input()
{
scanf("%d %d" ,&n ,&k);
Cle(a);
for(int i=0 ;i<n ;++i)
scanf("%d" ,&a[i]);
for(int i=0 ;i<n ;++i)
{
scanf("%d" ,&t);
if(t) sum+=a[i];
else
add(i ,a[i]);
}
}
int ope()
{
if(header->next->next == NULL)
return a[0];
int ti=k-1;
int temp=0;
low=header->next; high=low->next;
if(k != 0) temp+=low->key;
while(low != NULL)
{
while(high && low->num + ti >= high->num)
{
temp+=high->key;
high=high->next;
}
max=max<temp ?temp :max;
temp-=low->key;
low=low->next;
}
return max;
}
int main()
{
initial();
input();
printf("%d", ope()+sum);
return 0;
}