瞌睡 (網易筆試題)
題目描述
小易覺得高數課太無聊了,決定睡覺。不過他對課上的一些內容挺感興趣,所以希望你在老師講到有趣的部分的時候叫醒他一下。你知道了小易對一堂課每分鐘知識點的感興趣程度,並以分數量化,以及他在這堂課上每分鐘是否會睡著,你可以叫醒他一次,這會使得他在接下來的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);
}
}
}