做题记录(2)

1.最大数组和

注意:不是单次筛去的石头价值小,总的筛去的石头价值就一定最小,所以要比较总共筛去石头的价值

public class Main
{
  public static void main(String[] args) 
  {
    Scanner scan = new Scanner(System.in);
    //在此输入您的代码...
        int t=scan.nextInt();
        int []a=new int[200005];
        long []b=new long[200005];
        for(int i=0;i<t;i++)
        {
            int n=scan.nextInt();
            int k=scan.nextInt();
            long sum=0;
            for(int j=1;j<=n;j++)
            {
                a[j]=scan.nextInt();
                sum+=a[j];//先求出数组的总和
            }
            Arrays.sort(a,1,n+1);//先对数组进行排序
            for(int j=1;j<=n;j++)
                b[j]=b[j-1]+a[j];//排序后求前缀和,b[j]表示前j个数的和
            long ans=0,back=0;
            long mina=b[2*k];
            for(int j=1;j<=k;j++)
            {
                back+=a[n-j+1];//用来统计最大的几个
                ans=b[2*(k-j)]+back;
                mina=Math.min(ans,mina);//从枚举的每一次中取最小值
            }
            System.out.println(sum-mina);//数组的总和减去要筛选掉的最小值的结果就是最大
        }
    scan.close();
  }
}

2.大石头的搬运工

思路: 直接计算某点前后石头搬到当前位置的花费,然后比较出最小的花费

class stone//创建一个类,用来对石头的初始位置进行排序
{
    int w;
    int p;
    public stone(int w,int p)
    {
        this.w=w;
        this.p=p;
    }
}
public class Main
{
  public static void main(String[] args) 
  {
    Scanner scan = new Scanner(System.in);
    //在此输入您的代码...
    int n=scan.nextInt();//石头的数量
    stone []a=new stone[100005];
    for(int i=1;i<=n;i++)
    {
        int w=scan.nextInt();
        int p=scan.nextInt();
        a[i]=new stone(w, p);
    }
    Arrays.sort(a,1,n+1,((o1,o2)->o1.p-o2.p));//根据石头的位置排序,从小到大
    long []front=new long[100005];
    long []back=new long[100005];
    front[1]=a[1].w;
    back[n]=a[n].w;
    //cost1和cost2分别表示前面石头和后面石头移动到当前位置的费用
    long []cost1=new long[100005];
    long []cost2=new long[100005];
    //两个for循环分别计算将某点前面的石头和后面的石头搬到当前位置的花费
    for(int i=2;i<=n;i++)
    {
        front[i]=front[i-1]+a[i].w;
        cost1[i]=front[i-1]*(a[i].p-a[i-1].p)+cost1[i-1];
    }
    for(int i=n-1;i>=1;i--)
    {
        back[i]=back[i+1]+a[i].w;
        cost2[i]=back[i+1]*(a[i+1].p-a[i].p)+cost2[i+1];
    }
    long ans=Long.MAX_VALUE;
    for(int i=1;i<=n;i++)
    {
        //从所有点中找出花费最小的:
        ans=Math.min(ans,cost1[i]+cost2[i]);
    }
    System.out.println(ans);
    scan.close();
  }
}

3.泡澡

一开始这么写的,果然运行超时了 

class Shower
{
	int s;
	int t;
	int p;
	public Shower(int s,int t,int p)
	{
		this.s=s;//开始时间
		this.t=t;//结束时间
		this.p=p;//每分钟需要的热水量
	}
}
public class Main
{
	public static void main(String[] args)
	{
		Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
		int n=scan.nextInt();//洗澡的人数
		int w=scan.nextInt();//热水器的容量
		Shower []plan=new Shower[n+1];
		int s,t,p;
		int earliest=99999,latest=0;
		for(int i=1;i<=n;i++)
		{
			s=scan.nextInt();
			t=scan.nextInt();
			p=scan.nextInt();
			plan[i]=new Shower(s,t,p);
			earliest=Math.min(earliest, s);
			latest=Math.max(latest, t);
		}
		long sum=0;
		for(int i=earliest;i<=latest;i++)
		{
			sum=0;
			for(int j=1;j<=n;j++)
			{
				if(plan[j].s<=i&&i<=plan[j].t)
				{
					sum+=plan[j].p;
					if(sum>w)
					{
						System.out.println("No");
						break;
					}
				}
			}
			if(sum>w)
				break;
		}
        scan.close();
    }
}

要用差分数组

思路:加上原数组表示每分钟总共需要的热水,初始值都为0,可直接定义一个差分数组(初始值都为0),最后求前缀和得出原数组,遍历比较

注意:差分数组定义为int类型的话会有一个样例通不过。

public static void main(String[] args)
	{
		Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
		int n=scan.nextInt();//洗澡的人数
		int w=scan.nextInt();//热水器的容量
		int s,t,p;
		int latest=0;
		//原数组表示每分钟总共需要的热水,初始值都为0,所以可直接定义差分数组(初始值都为0)
		long []a=new long[200005];//定义为int类型会有一个样例通不过
		for(int i=1;i<=n;i++)
		{
			s=scan.nextInt();
			t=scan.nextInt();
			p=scan.nextInt();
			//找出最晚结束的泡澡时间:
			latest=Math.max(latest,t);
			//对差分数组进行处理,题目给定区间是左闭右开,因此t表示区间右端点的后一位
			a[s]+=p;
			a[t]-=p;
		}
		for(int i=0;i<=latest;i++)
		{
			if(i!=0)//防止访问i=0时i-1=-1越界
				a[i]+=a[i-1];//求前缀和还原数组
			if(a[i]>w)
			{
				System.out.println("No");
				break;
			}
			if(i==latest)//i为latest时所有人都已经结束,所以输出Yes
			{
				System.out.println("Yes");
			}
		}
        scan.close();
    }

4.肖恩的投球游戏

public static void main(String[] args)
	{
		Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
		int n=scan.nextInt();
		int m=scan.nextInt();
		int q=scan.nextInt();
		int x1,y1,x2,y2,c;
		int [][]a=new int[1005][1005];
		int [][]diff=new int[1005][1005];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
			{
				a[i][j]=scan.nextInt();
				diff[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
                //求二维差分数组:diff[i][j]=a[i][j]-左-上+左上
			}
		for(int i=1;i<=q;i++)
		{
			x1=scan.nextInt();
			y1=scan.nextInt();
			x2=scan.nextInt();
			y2=scan.nextInt();
			c=scan.nextInt();
			//处理二维差分数组:
			diff[x1][y1]+=c;
			diff[x1][y2+1]-=c;//右-c
			diff[x2+1][y1]-=c;//下-c
			diff[x2+1][y2+1]+=c;//右下+c
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				diff[i][j]+=diff[i-1][j]+diff[i][j-1]-diff[i-1][j-1];
				//二维数组求前缀和+上+左-左上
				System.out.print(diff[i][j]+" ");
			}
			System.out.println();
		}
        scan.close();
    }

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值