CodeForces#645 div.2(A~D)

A题

描述

在一个公园修建最少的路灯,照亮整片公园,路灯的照亮范围是所在边界的附近两块。
在这里插入图片描述
输入:第一行为本次测试用例数量(1<=t<=104),之后为公园的长宽(1<=n,m<=104)
输出需要的路灯数
在这里插入图片描述

思路

就跟以前看过一个盖方块的思维题一样给一个棋盘(国际象棋那种),然后用一个1*2的方块来逐一覆盖棋盘,方块之间不能有重叠或者漏盖,请问能否覆盖完全。
这个思维题很简单,如果这个面积可以被2整除,那必然可以完全覆盖,因为它的最小单位面积就是2。
再回到这道题,我们想要最少的路灯,自然也与上面同理,就是“方块”(灯光范围)之间不能有重叠,那么直接对面积除以2,如果不能被2整除,那么就单独用一盏灯照亮。


import java.util.Scanner;
 
/**
 * @创建人 YDL
 * @创建时间 2020/5/9 22:34
 * @描述
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for(int i=0;i<n;i++){
            int m = sc.nextInt();
            int nn = m*sc.nextInt();
            int ans = nn>>1;
            ans = (nn&1)==0?ans:ans+1;
            System.out.println(ans);
        }
    }
}

B题

描述

一个老太太M,想约人举行啥仪式,但是老太太们都有点牌面,必须当时能到场的人数大于或等于自己要求的人数才来(M和自己也算在其中),M可以自行选择约老太太的顺序。等价于约了就会闪现那种,老太太如果发现人数不足自己的要求就闪走,那么最后到场的能有多少个老太太。
输入:第一行t测试用例的数量(1≤t≤104),测试用例结构,第一行,老太太人数(1≤n≤105),第二行老太太的要求人数(1≤ai≤2⋅105).
输出:能到场的老太太人数k (1≤k≤n+1)
在这里插入图片描述

思路

这题就用贪心的思路,首先将老太太排序,优先邀请要求人数少的,不过需要注意的是,人数有时会低于要求,可是之后要求相同的老太太都邀请来了,那就没问题,所以得考虑到最后。

import java.util.Arrays;
import java.util.Scanner;
/**
 * @创建人 YDL
 * @创建时间 2020/5/9 22:34
 * @描述
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for(int i=0;i<n;i++){
            int n1 = sc.nextInt();
            int[] nais = new int[n1];
            for(int j=0;j<n1;j++){
                nais[j] = sc.nextInt();
            }
            Arrays.parallelSort(nais);
            int ans = 1,pre = 1;
            for(int j=0;j<n1;j++){
                if(nais[j]<ans+pre){
                    ans+=pre;
                    pre = 1;
                }else{
                    pre++;
                }
            }
            System.out.println(ans);
        }
    }
}

C题

描述

给定了一个矩阵的规则,大概就是斜着递增。
在这里插入图片描述
然后给出某两个坐标,求起始点到终点的可能路径(经过的点的和不相同)和。
输入:测试样例的数量t (1≤t≤57179) ,测试样例的格式起始坐标(x1,y2),终点坐标(x2,y2)(1≤x1≤x2≤109, 1≤y1≤y2≤109)
输出:路径之和
在这里插入图片描述

思路

做的时候没细看题目无脑想成计数dp了…这题非要用dp也可以再用一个Set存储到达目标位置时的和。不过就有点暴力了。看了下数据规模,肯定过不了的。
那么只能取巧,选择都是在每一层选一个点(斜着算一层),而每层对应每层选择至少会比上一次选择大2,所以我们并不需要老实的模拟从(x1,y1)->(x2,y2).有个规律就是所得结果必然会是一段连续数列,因为每次选择都会在上一层原基础上加2,这个所有路径都是,所以都可以忽略不记,本质上最每层斜着过来就是1,2,3,4,5…

11111
22222
33333

本质上就是求这段连续的和为多少,可以算出为(x-1)+Σiy i —— Σiy i+y*(x-1),求得为(x-1)*(y-1)+1.

import java.util.Arrays;
import java.util.Scanner;
/**
 * @创建人 YDL
 * @创建时间 2020/5/9 22:34
 * @描述
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for(int i=0;i<n;i++){
            int x0 = sc.nextInt();
            int y0 = sc.nextInt();
            int x1 = sc.nextInt();
            int y1 = sc.nextInt();
            long ans = (long)(x1-x0)*(y1-y0)+1;
            System.out.println(ans);
        }
    }
}

D题

描述

去一个城市旅行,但是那个城市的日历很奇怪,每个月的日期不一样,在每月的i日去,可以获得i的快乐指数,可以停留x日,这次旅行最多能够获取多少次快乐指数?(可以跨年)
输入:
第一行:一年有几月(n (1≤n≤2⋅105)),能够停留几日(x 少于一年的总天数)
第二行:每月天数(d1,d2,d3… (1≤di≤106) )
输出:快乐指数
在这里插入图片描述

思路

当为最大时,开始点或者结束点肯定是在一个月份的结束位置。
因为不同大小的月份数,它们前面的都是一致的,只有后面的天数才是最有价值的(比较大嘛),所以我们可以尝试,以每个月都作为开头,然后查找到可供它选择的所有天数。
因为可以跨年嘛,所以这是个环,先把环展开(把读入的月份数复制一份。)而且天数肯定是随着前面所需天数递增的,如果能够度过这个月份,那么和为((1+di)*di )/2,如果不行,那么只取剩余天数的等差数列和。
我们也不用每个月都算一次,直接将完整的月份等差数列和与之前月份的和存入一个数组中,那么如果要求某个区间月份的天数和就可以直接相减了。
因为这是个单递增的数列,所以我们可以使用二分查找的方式,查找选择某月作为结尾时,它能选择到的范围。
然后再用这个范围的总天数去减去x,这个差就是开始的天数之前的天数。
再用范围总天数减去之前的天数和即可。

import java.util.Scanner;

/**
 * @创建人 YDL
 * @创建时间 2020/5/9 22:34
 * @描述
 */
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
         int n = sc.nextInt();
         long x = sc.nextLong();
         long[] m = new long[(n<<1)+1];
         long[] days = new long[(n<<1)+1];
         long[] sums = new long[(n<<1)+1];
         for(int i=1;i<=n;i++){
             m[i] = sc.nextLong();
             m[i+n] = m[i];
         }
         int n2 = (n<<1);
         for(int i=1;i<=n2;i++){
             days[i] = days[i-1]+m[i];
             sums[i] = sums[i-1]+((m[i]+1)*m[i]>>1);
         }
         long max =0;
        for(int i=n2;i>=n+1;i--){
            int left=1;
            int right=i;
            int ans=i;
            while(right>=left){
                int mid=left+right>>1;
                if(days[i]-days[mid]<x){
                    right=mid-1;
                    ans=mid;
                }
                else {
                    left = mid + 1;
                }
            }
            long temp=days[i]-days[ans-1]-x;
            max=Math.max(sums[i]-sums[ans-1]-(((temp+1)*temp>>1)),max);
        }
         System.out.println(max);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值