2022 -1-9 郑轻第七次周赛部分题解JAVA

 2887: 分糖果

题目描述

    sjjj、jljj和ylgg成功夺得首块CCPC银牌,这是个值得纪念的时刻。sjjj很开心,决定给ACM的队员们分些糖果吃(据说吃了sjjj的糖可以拿牌子)。

    已知sjjj手里有无数块糖果(有钱任性),队里有 m 个人,sjjj不想简简单单的分糖果,于是想了个法子,他决定将一些糖果放到一个 n 行 n 列二维矩阵中,第 i 行,第 j 列的区域内就放 i^2 + j^2 个糖果。

    sjjj想让你告诉他 n * n 个区域有多少个区域内的糖果可以恰好平均分给 m 个队员。(sjjj当然知道结果,他就是想单纯的为难你)

输入

输入一行包含两个整数 n(1 <= n <= 109),m(1 <= m <= 103) 。

输出

输出一个整数,糖果可以恰好平均分给 m 个队员的区域数量。

样例输入 Copy

6 5

样例输出 Copy

13

提示

如下区域内的糖果可以恰好平均分给队员

  • (1,2)和(2,1),1^2 + 2^2=5,恰好可以平均分给5个队员;

  • (1,3)和(3,1);

  • (2,4)和(4,2);

  • (2,6)和(6,2);

  • (3,4)和(4,3);

  • (3,6)和(6,3);

  • (5,5);

 解析:由题意得   \left ( i^2+j^2 \right )%m=0

可推理:\left (i^2%m+j^2%m \right )%m=0\Rightarrow \left ( i%m*i%m+j%m*j%m \right )%m=0

通过推理得出的公式可得:只需要找出0~m-1的余数进行判断即可,这里用cnt[]数组来存储其余数的个数,然后只需要判断余数平方相加是否对m取余为零,若是则表明该组合可以,那么直接将他们的组合个数求出来即可,即ans+=(long)cnt[i]*cnt[j]; 

注:因为两个数相乘可能会爆int,所以需要转化一下,否则可能出现测试样例不通过的情况。

import java.util.Scanner;

public class Main{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		int n=cin.nextInt();
		int m=cin.nextInt();
		
		long ans=0;
		int cnt[]=new int[m];
		
		//得到n中有多少个0~m-1
		for(int i=0;i<m;i++)cnt[i]=n/m;
		//将n~n-n%m之间的数枚举一下,因为上一个循环只是枚举1~i(i为1~n中%m==0最大的数);
		for(int i=n;i>n-n%m;i--) {
			cnt[i%m]++;
		}
		
		for(int i=0;i<m;i++) {
			for(int j=0;j<m;j++) {
				if((i*i+j*j)%m==0) {
					//组合得到有多少种答案;
					ans+=(long)cnt[i]*cnt[j];
				}
			}
		}
		
		System.out.println(ans);
	}

}

2889: 移动元素

题目描述

    OH哥哥最近迷上了移动元素,通过移动元素来找规律。这天,他发现对于一个给定的数组,选择其中任意一个元素,并将其移动到数组中任意一个位置(也可以保持不动),便有可能将该数组分为前后两个非空部分,并使前一部分的各元素之和等于后一部分的各元素之和(此操作只允许进行一次)。

    那么,如果给你一些数组,你能能帮助OH哥哥找出哪些数组可以达成吗?

输入

第一行包含整数 T(1 <= T <= 20),表示共有 T 组测试数据。

每组数据第一行包含整数 n(1 <= n <= 105) 。

第二行包含 n 个整数a1,a2,...an  (1 <= ai <= 109)。

输出

每组数据输出一行结果,如果可以达成输出YES,否则输出NO。

样例输入 Copy

3
3
1 3 2
5
1 2 3 4 5
5
2 2 3 4 5

样例输出 Copy

YES
NO
YES 

解析:因为分割,只有偶数才能进行分割,移动元素可以从左往右移动,也可以从后往前移动,只需要判断 前缀和 后缀和 是否成立即可,通过p[n]/2-(p[n]-p[i])\Rightarrow p[i]-p[n]/2为判断条件,看a[1]-a[i]中是否存在这个数,而判断我们就可以使用set

 

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;

const int N=100010;
//a[]数组用来存储正序的数,b[]数组用存储逆序的数,便于后续得到前缀和,后缀和 
int a[N],b[N];

typedef long long LL;
LL p[N];
int n;

bool check(int *arr){
	for(int i=1;i<=n;i++){
		//得到该数组的前缀和 
		p[i]=p[i-1]+arr[i]; 
	}
	//使用集合判断是否符合条件 
	set<LL> s;
	s.insert(0);
	
	for(int i=1;i<=n;i++){
		//每次循环判断的是0-i之间是否有符合的数 
		s.insert(arr[i]);
		if(s.count(p[i]-p[n]/2))return true;
	}
	return false;
}


int main(){
	IOS; cin.tie(0);
	int t;
	cin>>t;
	
	while(t-->0){
		cin>>n;
		for(int i=1,j=n;i<=n&&j>=1;i++,j--){
			cin>>a[i];
			b[j]=a[i];
			
			p[i]=p[i-1]+a[i];
		}
		//保证数组之和是偶数才能进行分割判断; 
		if(p[n]%2!=0)printf("NO\n");
		else{
			//如果前缀和和后缀和有一个满足条件 ,即可以进行分割 
			if(check(a)||check(b))printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
}

2890: 数字反转

题目描述

大嘴猫吃完金币,玩完卡牌之后心满意足,OH很是嫉妒,于是强迫大嘴猫完成以下任务:

给大嘴猫一个数(整数、小数、分数),让它找出该数的反转。

  • 整数反转是将所有数位对调。

  • 小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分。

  • 分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母。

输入

一个非负数 s。 

输出

一个数,即 s 的反转数。

样例输入 Copy

20220109

样例输出 Copy

90102202

提示

样例2:
输入:14.00
输出:41.0
样例3:
输入:13/14
输出:31/41 

  • s是整数,不大于20位

  • s是小数,整数部分和小数部分均不大于10位

  • s是分数,分子和分母均不大于10位,数据分母保证不为0,不用约分

  • 对于所有部分而言,如果除了0没有别的数,那么只保留一个0,注意前导零也要去掉

解析:反转(使用StringBuffer)并不难,只需要注意两个点:

           1.前导零的处理:在本题中可将反转的字符串直接转化为int数据类型(也可以使用正则表达式),便可以解决前导零的问题。

           2.使用split进行小数点切割时记得注意使用“\\.”。

import java.util.Scanner;

public class Main{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		String s=cin.nextLine();
		if(s.indexOf(".")!=-1) {
			String ss[]=s.split("\\.");
//			System.out.println(ss[0]);
			StringBuffer sb=new StringBuffer(ss[0]);
			sb.reverse();
			int m=Integer.parseInt(ss[1]);
			StringBuffer sb1=new StringBuffer(String.valueOf(m));
			sb1.reverse();
			int x=Integer.parseInt(sb1.toString());
			System.out.println(Integer.parseInt(sb.toString())+"."+x);
		}
		else if(s.indexOf("/")!=-1) {
			String ss[]=s.split("/");
			StringBuffer sb=new StringBuffer(ss[0]);
			sb.reverse();
			StringBuffer sb1=new StringBuffer(ss[1]);
			sb1.reverse();
			
			System.out.println(Integer.parseInt(sb.toString())+"/"+Integer.parseInt(sb1.toString()));
		}else {
			StringBuffer sb=new StringBuffer(s);
			sb.reverse();
			System.out.println(Integer.parseInt(sb.toString()));
		}
	}

}

2892: 大嘴猫吃金币

题目描述

  地面上有排成一条直线的n个金币,金币有不同的价值(甚至是负的),大嘴猫想用它的大嘴来吃这些金币。但是大嘴猫只能张一次嘴,所以它只能吃连续一段的金币。你知道大嘴猫最多能吃多大价值的金币吗?

输入

第一行一个整数n,表示有n个金币 。1 <= n <= 1000000。

接下来n行每行一个整数x,表示金币的价值。x在int范围内。

输出

一行一个整数,表示最多吃下金币的价值。

样例输入 Copy
4
1 2 -1 10
样例输出 Copy
12

解析:因为是求一段区间的最大值,就需要我们对区间进行维护,那么保证sum<0时,sum=0即可

import java.util.Scanner;

public class Main{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		int n=cin.nextInt();
		long a[]=new long[n+1];
		long ans=0;
		long sum=0;
		for(int i=1;i<=n;i++) {
			a[i]=cin.nextLong();
			if(sum+a[i]>=0)sum+=a[i];
			else sum=0;
			ans=Math.max(ans,sum);
		}
		
		System.out.println(ans);
	}

}

 

2894: 通项公式

三角形数

Tn= n(n + 1)/2

1,3,6,10,15…

四边形数

Fn= (n + 1)2

1,4,9,16,25…

六边形数

Hn= n(2n-1)

1,6,15,28,45…

求第n个同时是三角形数字,四边形数字,六边形数字的数字。

可以验证的是,T49 = F34 = H25 = 1225。

输入
一个整数N。 1 <= N <= 3。
输出
一行一个整数,代表第n个同时是三角形数字,四边形数字,六边形数字的数字。
样例输入 Copy
1
样例输出 Copy
1125
解析:因为通过题意可知,至于要求出 同时是三角形数字,四边形数字,六边形数字的数字三个即可,所以循环100010次足够了。因为六边形数字一定是三角形数字,那么我们可以转化为求同时是四边形数字和六边形数字即可。
import java.util.HashMap;
import java.util.Scanner;

public class Main{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		int n=cin.nextInt();
		HashMap<Long,Integer> map=new HashMap<>();
		long a[]=new long[4];
		for(int i=1;i<100005;i++) {
			map.put((long) ((long)i*(2*i-1)),1);
		}
		int j=1;
		
		for(int i=1;i<100005;i++) {
			long x=(long)(i+1)*(long)(i+1);
			if(map.containsKey(x)) {
				a[j++]=x;
				if(j==4)break;
			}
		} 
		
		System.out.println(a[n]);
	}

}

          

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值