NOJ1366: [蓝桥杯2018初赛]倍数问题-(思维)
题目描述
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。
但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。
现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数
使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。
但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。
现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数
使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。
输入
第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。
1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。
第二行 n 个正整数,代表给定的 n 个数。
1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。
输出
输出一行一个整数代表所求的和。
样例输入 Copy
4 3
1 2 3 4
样例输出 Copy
9
思路:假设三个数分别是a,b,c;(a+b+c)%k=(a%k+b%k+c%k)%k=0。限定了k<1000则每个数的模数必然<k,最多取三个,对于每种模数保留三个最大的情况。还要对三个数的模数想等情况做出判断,互不相等、有两个相等、全部不相等。用一个num数组记录模数的个数看看三个数的模数是否满足需求。A组第9题居然能想出来,多亏之前的k倍区间给我提供了模数和的思路。
import java.util.*; import java.util.Collections; public class Main{//1366: [蓝桥杯2018初赛]倍数问题 public static void main(String []args){ Scanner scan=new Scanner(System.in); int [][] mod=new int[1005][3];//相同模数保留前三大的 int [] num=new int[1005]; int n=scan.nextInt(); int p=scan.nextInt(); for(int i=1;i<=n;i++) { int x=scan.nextInt(); int r=x%p; num[r]++; //找到这个模数的最小的一个数 和 下标 int minn=Integer.MAX_VALUE; int idx=0; for(int j=0;j<3;j++) { if(minn>mod[r][j]) { idx=j; minn=mod[r][j]; } } if(minn<x)//x比原来的大,取代原来的那个 mod[r][idx]=x; } long maxx=0; for(int i=0;i<p;i++) Arrays.sort(mod[i]); //双重暴力 最后一个数用减法即离散化即可定位模数下标 for(int i=0;i<p;i++) { for(int j=0;j<p && num[i]!=0;j++) { long now=0; int k=p-((i+j)%p); if(i==j && i==k ) {///三个模数都相同 if(num[i]>=3) now=mod[i][2]+mod[i][1]+mod[i][0]; }else if(i==j && i!=k) {//前两个模数相同 if(num[i]>=2 && num[k]>=1) now=mod[i][2]+mod[i][1]+mod[k][2]; }else if(i!=j && j==k) {//后两个模数相同 if(num[i]>=1 && num[j]>=2) now=mod[i][2]+mod[j][2]+mod[j][1]; }else if(i==k && i!=j){//第一个和第三个相同 if(num[i]>=2 && num[j]>=1) now=mod[i][2]+mod[i][1]+mod[j][2]; }else {//三个模数都不同 if(num[i]>=1 && num[j]>=1 && num[k]>=1 ) now=mod[i][2]+mod[j][2]+mod[k][2]; } if(maxx<now) maxx=now; } } System.out.println(maxx); } }
天上不会掉馅饼,努力奋斗才能梦想成真。