鼠鼠我呀题解

鼠鼠我呀

题目描述

在一个叫做酱西功爷枝叶鸡树学院的地方有n只小动物,要么是鼠鼠,要么是鸭鸭,从1到n编号,每只小动物有个体重 a i a_i ai

在这个学校里,存在一种神奇的魔法,可以将编号位于某个区间 [ l , r ] [l,r] [l,r]内的所有鼠鼠都变为鸭鸭,鸭鸭都变为鼠鼠(魔法并不会改变体重)。

现在你可以施放这个魔法至多1次。(也可以不施放)

问最终鸭鸭的总重量最多是多少?

输入格式

第一行一个整数T表示样例个数。 ( 1 ≤ T ≤ 10 ) (1≤T≤10) (1T10)

对于每个样例:

第一行一个整数n表示小动物的个数。( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105)

第二行 n n n个整数,表示第 i i i个小动物的类型。0表示鼠鼠,1表示鸭鸭。

第三行 n n n个整数,表示第 i i i个小动物的体重 a i a_i ai。( 1 ≤ a i ≤ 1 0 9 1≤a_i≤10^9 1ai109)

输出格式

对于每个样例一行一个整数表示答案。

样例输入

2
3
0 0 0
1 2 3
4
0 1 0 0
2 5 6 5

样例输出

6
16
题目分析

假设原本所有鸭鸭的重量是sum,操作后形成的偏移是fix,即经过至多1次操作后鸭鸭的总重量是sum+fix,这里的fix最小是0,因为如果操作后的fix是负数,会使得鸭鸭的总重量减少,倒不如不操作,直接是sum就可以了。

来看这个fix应该怎么求。以样例的第二组数据为例,如果操作区间是[0,4],那么每个位置对应的偏移量分别为2,-5,6,5。总的偏移量为2-5+6+5=8。如果操作区间是[1,2],总的偏移量为-5+6=1。其实要求某个区间的偏移量就是数组[2,-5,6,5]对应区间的区间和。这里的[2,-5,6,5]也叫做偏移量数组,因为对于位置i的值而言,如果他是鸭鸭,一次操作后就变为了鼠鼠,那么之前累加上的他的重量应该减去,所以偏移量就是负的该位置的重量也就是-a[i],如果他是鼠鼠,一次操作后就变为了鸭鸭,他的重量应该累加上,所以偏移量就是该位置的重量也就是a[i]。所以我们可以求一下偏移量数组的前缀和,然后利用前缀和求最大的偏移量区间和,也就是一开始说的fix,累加到原始的重量和sum里面就好。

假设偏移量的前缀和数组是pre[i],那么偏移量的区间和[l,r]就用pre[r]-pre[l-1],如果我们遍历l和r的话,双层嵌套for循环会超时,所以这里应该采用类似双指针的做法,假设固定了r,要想pre[r]-pre[l-1]最大,需要pre[l-1]是区间[1,l-1]里面最小的那个数,用mi表示,关键代码如下,

fix=0;mi=0;
for(int i=1;i<=n;i++)  
		{
			fix=max(fix,s[i]-mi);//i固定时,mi是下标比i小的数中的最小值
			mi=min(mi,s[i]);
		}

fix最小是0,所以初始化为0。这里的mi最小值也为0,mi为0时表示的是区间[1,i]的区间和,如果mi不为负数,说明s[i]-mi会变小,即比s[i]本身小,倒不如直接用s[i],s[i]表示的就是前i项之和,也是区间和。

题目代码
#include 
using namespace std;
typedef long long ll;

const int N=1e5+10;
ll g[N],w[N],s[N],p[N];
ll sum,fix,mi;

int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>g[i];
        for(int i=1;i<=n;i++)cin>>w[i];
        for(int i=1;i<=n;i++)
		{
			s[i]=s[i-1]+(g[i] == 1 ? -1 : 1)*w[i]; //计算出施加魔法后的偏移值(鸭子重量),如果原来是1(鸭子)就要减去,原来是0(鼠)就加上
		}
		sum=0;
        for(int i=1;i<=n;i++) {
            sum+=w[i]*g[i];
        }
        fix=0,mi=0;
        for(int i=1;i<=n;i++)
		{
			fix=max(fix,s[i]-mi);
			mi=min(mi,s[i]);
		}

        cout<

代码有一个易错点,因为变量都是全局变量,所以sum,fix,e在每一组测试样例中都要重置为初始值。

package 前缀和和差分;

import java.util.Scanner;

public class 鼠鼠我鸭 {


	static  int N=(int) (1e5+10);
	static long[] g=new long[N],w=new long[N],s=new long[N],p=new long[N];
	static long sum,fix,mi;
public static void main(String[] args) {
	 int t;
	 Scanner scanner = new Scanner(System.in);
	 t = scanner.nextInt();
	    while(t-- > 0){
	        int n;
	        n = scanner.nextInt();
	        for(int i=1;i<=n;i++)g[i]=scanner.nextLong();
	        for(int i=1;i<=n;i++)w[i]=scanner.nextLong();
	        for(int i=1;i<=n;i++)
			{
				s[i]=s[i-1]+(g[i] == 1 ? -1 : 1)*w[i]; //计算出施加魔法后的偏移值(鸭子重量),如果原来是1(鸭子)就要减去,原来是0(鼠)就加上
			}
			sum=0;
	        for(int i=1;i<=n;i++) {
	            sum+=w[i]*g[i];
	        }
	        fix=0;mi=0;
	        for(int i=1;i<=n;i++)  //从第一个遍历到最后,计算出最大最小值
			{
				fix=Math.max(fix,s[i]-mi);
				mi=Math.min(mi,s[i]);
			}
            System.out.println(sum+fix);
	    }

}
}

你可能感兴趣的:(算法,数据结构)