1. 程式人生 > >瞌睡 (網易筆試題)

瞌睡 (網易筆試題)

題目描述

小易覺得高數課太無聊了,決定睡覺。不過他對課上的一些內容挺感興趣,所以希望你在老師講到有趣的部分的時候叫醒他一下。你知道了小易對一堂課每分鐘知識點的感興趣程度,並以分數量化,以及他在這堂課上每分鐘是否會睡著,你可以叫醒他一次,這會使得他在接下來的k分鐘內保持清醒。你需要選擇一種方案最大化小易這堂課聽到的知識點分值。

輸入

第一行 n, k (1 <= n, k <= 10^5) ,表示這堂課持續多少分鐘,以及叫醒小易一次使他能夠保持清醒的時間。 第二行 n 個數,a1, a2, ... , an(1 <= ai <= 10^4) 表示小易對每分鐘知識點的感興趣評分。 第三行 n 個數,t1, t2, ... , tn 表示每分鐘小易是否清醒, 1表示清醒。

輸出

小易這堂課聽到的知識點的最大興趣值

輸入樣例 1 

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

輸出樣例 1

16                                                                                                                                                                                                    

題意:

 每分鐘都會有兩個量,一個是小易對這一分鐘知識點的感興趣評分,以及小易是否清醒,輸入的k為叫醒小易後他能保持清醒的時間,只能叫醒小易一次,要求得出小易這堂課聽到的知識點的最大興趣值。

方法一:最先想到的就是一個很暴力的方法,先求出小易醒著的的興趣值總和sum,然後從頭開始遍歷每一分鐘,判斷是否清醒,如果為不清醒,那麼就遍歷接下來k個值,把這k個值未醒著的分值加到前面的sum上,與記錄的最大的興趣值比較並不斷更新最大值。但是這個絕對就會超時,確實超時了。

暴力超時程式碼:

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
	   
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int k=in.nextInt();
		int[] value=new int[n];    //知識點的興趣值
		int[] wake=new int[n];     //每分鐘是否清醒
		for(int i=0;i<n;i++)
			value[i]=in.nextInt();
	    for(int i=0;i<n;i++)
	        wake[i]=in.nextInt();
	    int sum=0;
	    for(int i=0;i<n;i++)
	    {
	    	if(wake[i]==1)sum+=value[i];
	    }
	    int max=sum;
	    for(int i=0;i<n;i++)
	    {
	    	if(wake[i]==0)
	    	{
	    		int m=sum;
	    		for(int j=i;j<Math.min(i+k, n);j++)
	    		{
	    			if(wake[j]==0)m+=value[i];
	    		}
	    		if(m>max)max=m;
	    	}
	    	
	    }
	    System.out.println(max);
	}

}

方法二:可以定義3個數組,長度都為n。leftv陣列是表示從左邊開始到右清醒時興趣值的累加和,rightv陣列是表示從右邊開始到左清醒時興趣值的累加和,tolv表示從左到右所有興趣值的累加和。

       然後當我們遍歷到為未醒著的位置i時,那麼這時的總的興趣值為3部分之和:leftv[i-1] + rightv[i+k] + (tolv[i+k-1] - tolv[i-1])。最重要的就是考慮邊界問題,第一部分的值為第i分鐘左邊的值,左邊界的問題就是要考慮i-1不能小於0,如果小於0,那麼左邊的和就不是加leftv[i-1]而是加0,第二部分的值就是第i分鐘右邊得值,右邊界的問題就是要考慮i+k要小於n,如果大於n,那麼右邊得和就不是加rightv[i+k]而是加0,最後一部分就是i與i+k之間的興趣值的和,tolv[Math.min(i+k-1, n-1)]-(i<1?0:tolv[i-1]),也是需要考慮邊界問題。

  可AC的程式碼:

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int k=in.nextInt();
		int[] value=new int[n];    //知識點的興趣值
		int[] wake=new int[n];     //每分鐘是否清醒
		for(int i=0;i<n;i++)
			value[i]=in.nextInt();
	    for(int i=0;i<n;i++)
	        wake[i]=in.nextInt();
	    int sum=0;
      
	    int[] leftv=new int[n];            //從左邊開始統計此分鐘之前清醒時所有的興趣值
	    for(int i=0;i<n;i++){
	    	if(wake[i]==1)sum+=value[i];
	    	leftv[i]=sum;
	    } 
       
	    int[] rightv=new int[n];         //從右邊開始統計此分鐘之前清醒時所有的興趣值
	    sum=0;
	    for(int i=n-1;i>=0;i--)
	    {
	    	if(wake[i]==1)sum+=value[i];
	    	rightv[i]=sum;
	    }
      
	    int[] tolv=new int[n];         //記錄此分鐘之前的清醒和未清醒所有的興趣值
	    sum=0;
	    for(int i=0;i<n;i++)
	    {
	       sum+=value[i];
	       tolv[i]=sum;
	    }
      
	    if(n==0)                 //如果n為0,結果一定為0
	    {
	    	System.out.println(0); 
	    }
	    else if(k==0)                 //如果K為0,那麼結果就是所有清醒時的興趣值
	    {
	    	System.out.println(leftv[n-1]);
	    }
	    else                         //n不為0,K也不為0
	    {
	    	int res=0;
		    for(int i=0;i<n;i++)
		    {
		    	if(wake[i]==0)
		    	{
		    		int m=0;
		    		if(i-1<0)m+=0;      //考慮左邊界的問題,
		    		else m+=leftv[i-1];
		    		if(i+k>=n)m+=0;     //考慮右邊界的問題
		    		else m+=rightv[i+k];
		    		m+=tolv[Math.min(i+k-1, n-1)]-(i<1?0:tolv[i-1]);
		    		if(m>res)res=m;
		    	}
		    }
	        System.out.println(res);
	    }
	}

}