赞
踩
注:1.P8649 K倍区间答案参考于“晏秋”,P8742 砝码称重答案参考于“一只风里”,感谢两位大佬提供的解法!
2.如有不正确的地方,欢迎指正,谢谢!
- import java.util.Scanner;
- public class Mian {
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- int n = scan.nextInt();//输入整数的个数
- int[] A = new int[n];//用一个数组接收这些整数
- int pre = 0;
- long[] sum = new long[n];
-
- //输入整数
- for(int i = 0;i < n;i++) {
- int num = scan.nextInt();
- A[i] = num;
- pre += num;
- sum[i] += pre;//求出每个整数对应的前缀和
- }
-
- //用前缀和数组进行优化
- //a1*a2 + a1*a3 + ... + a1*an
- //a1*(a2 + a3 + ... +an) = a1*(sum(n) - sum(1))
- long total = 0;//用于接收最终的结果——所求的和
- for(int i = 0;i < n;i++) {
- total += A[i] * (sum[n - 1] - sum[i]);
- }
- System.out.println(total);
-
- }
-
- }
答案参考:晏秋
- import java.util.Scanner;
- public class main {
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- int N = scan.nextInt();
- int K = scan.nextInt();
- int[] A = new int[N];
- long sum = 0;
- long[] B = new long[K];//存放各个余数的个数(这里不太理解为什么要用long)
- for(int i = 0;i < N;i++) {
- A[i] = scan.nextInt();
- sum += A[i];//把前缀和求出来
- B[(int)(sum % K)]++;
- }
-
- long count = 0;//接收结果
- count = B[0];//余数为0的个数(余数为0则必定为K的倍数)
- for(int i = 0;i < K;i++) {
- //两个同余的数相减一定为K倍区间
- //用排列组合公式Cn,即从具有相同余数的前缀和里取出两个前缀和进行相减
- count += (B[i] * (B[i] - 1)) / 2;
- }
- System.out.println(count);
-
- }
-
- }
并查集主要用于不相交集合的合并问题
1.初始化,即将每个节点的祖先节点指向自己
2.查询祖先节点find
3.合并两个节点:将一个节点的祖先节点指向另一个节点的祖先节点
- import java.util.Scanner;
- public class Main {
- static int[] fa;
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- int m = scan.nextInt();
- int n = scan.nextInt();
- int k = scan.nextInt();
- //用二维数组存放连根数据
- int[][] arr = new int[k][2];
- for(int i = 0;i < k;i++) {
- int a = scan.nextInt();
- int b = scan.nextInt();
- arr[i][0] = a;
- arr[i][1] = b;
- }
-
- //初始化:将每个植物节点的祖先节点指向自己
- //为了方便,数组0位置不使用
- fa = new int[m * n + 1];
- for(int i = 1;i < fa.length;i++) {
- fa[i] = i;
- }
-
- int count = m*n;
- for(int i = 0;i < k;i++) {
- int x_fa = find(arr[i][0]);
- int y_fa = find(arr[i][1]);
- //当x与y的祖先节点相同时,无需将x的祖先节点指向y的祖先节点,count无需减1
- if(x_fa == y_fa) {
- continue;
- }
- else {
- //让x的祖先节点指向y的祖先节点
- fa[x_fa] = y_fa;
- count--;
- }
-
- }
-
- System.out.println(count);
- }
- public static int find(int node) {
- if(fa[node] == node) {
- return node;
- }
- else {
- //比如1→5→6,1的父节点为5,则find(5),即继续寻找5的父节点
- //直到找到最终节点6,6的父节点指向自己,则进入if语句,return 6;所以fa[1] = 6;
- fa[node] = find(fa[node]);//该步进行了路径压缩
- return fa[node];
- }
- }
-
- }
- import java.util.Scanner;
- public class Main {
- static int N;
- static int K;
- static int[] H;
- static int[] W;
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- N = scan.nextInt();
- K = scan.nextInt();
- H = new int[N];//存放各块巧克力的长
- W = new int[N];//存放各块巧克力的宽
-
- for(int i = 0;i < N;i++) {
- int h = scan.nextInt();
- int w = scan.nextInt();
- H[i] = h;
- W[i] = w;
- }
-
- System.out.println(find(1,100000));
-
- }
-
- //二分查找
- public static int find(int l,int r) {
- int ans = -1;
- int mid = 0;
- while(l <= r) {
- mid = (l + r) / 2;
- if(account(mid)) {
- //当以mid为边长分出巧克力块数大于孩子数时
- //继续向右边寻找更大的边长
- ans = mid;
- l = mid + 1;
- }
- else {
- //当以mid为边长分出巧克力块数小于孩子数时
- //向左寻找(将边长缩小一点,快数会多一点)
- r = mid - 1;
- }
- }
- return ans;
- }
-
- public static boolean account(int a) {
- int count = 0;
- for(int i = 0;i < N;i++) {
- count += (H[i] / a)*(W[i] / a);
- }
- if(count >= K) {
- return true;
- }
- else {
- return false;
- }
- }
-
- }
答案参考:一只风里
- import java.util.Scanner;
- import java.lang.reflect.Array;
- import java.util.ArrayList;
- import java.util.HashSet;
- public class Main {
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- int N = scan.nextInt();
- int[] fama = new int[N];//用于存放各个砝码的重量
- for(int i = 0;i < N;i++) {
- fama[i] = scan.nextInt();
- }
-
- HashSet<Long> set = new HashSet<Long>();
- set.add(0L);
- for(int i = 0;i < N;i++) {
- //不能直接使用set的迭代器遍历,迭代器不能及时发现set的更新
- //(自己的理解,如不对请指正,谢谢!)
- ArrayList<Long> list = new ArrayList<Long>(set);
- for(long k:list) {
- set.add(fama[i] + k);
- set.add(Math.abs(k - fama[i]));
- }
- }
- set.remove(0L);
- System.out.println(set.size());
- }
-
- }
- import java.util.Scanner;
- public class Main {
- static int sum;//统计路径
- static int[] node;//用于标记节点是否已访问
- static int[][] map;//用于标记两个节点之间是否有线路
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner scan = new Scanner(System.in);
- int N = scan.nextInt();
- int M = scan.nextInt();
- //为了方便,数组0位置不使用,从1开始
- node = new int[N + 1];
- map = new int[N + 1][N + 1];
- for(int i = 0;i < M;i++) {
- int u = scan.nextInt();
- int v = scan.nextInt();
- map[u][v] = 1;//1表示节点之间有线路
- map[v][u] = 1;
- }
-
- for(int i = 1;i < N + 1;i++) {
- node[i] = 0;//node数组初始化,0表示未访问,1表示已访问
- }
-
- for(int i = 1;i < N + 1;i++) {
- dfs(i,i,0);
- }
- System.out.println(sum);
- }
- //传入三个参数,start表示起始节点,temp表示当前节点,step表示步长(即连接节点的线路条数)
- //1.判断是否为终点,非终点时继续递归调用dfs
- //2.递归调用dfs前需要将当前节点设为已访问,为了防止走回头路;
- // 调用结束后需要将当前节点设为未访问,为了探索其它路径时可以访问该节点
- //此题注意:当步长为2时,需要判断当前节点与起始节点是否有线路,如果有,则sum++
- public static void dfs(int start,int temp,int step) {
-
- if(step == 3) {
- sum++;
- return;
- }
- else if(step == 2) {
- if(map[temp][start] == 1) {
- sum++;
- }
- for(int k = 1;k < map[temp].length;k++) {
-
- if(map[temp][k] == 1 && node[k] == 0) {
- node[temp] = 1;
-
- dfs(start,k,step + 1);
- node[temp] = 0;
- }
- }
-
- }
- else {
- for(int k = 1;k < map[temp].length;k++) {
-
- //如果temp和k之间有线路,且k未访问
- if(map[temp][k] == 1 && node[k] == 0) {
-
- node[temp] = 1;
- //当前节点变为k,步长+1
- dfs(start,k,step + 1);
- node[temp] = 0;
- }
- }
- }
- }
-
- }
有两个测试点未通过,显示超出空间限制,请问大家有什么更好的解吗?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。