解题思路:气死我了,写道一半,突然没网了,然后写的东西全不见了,生气!
这道题,暴力不可以,所以需要想办法。用数学思维来想一想
1,2,3,4,5 如果叫你求其中任何一个区间,你可能会选择一个一个的去数,然后相加,这也是我们暴力求解的做法,但是数据多了呢?如果让你去算,你怎么办?比如我给你一个下标[2,30],叫你求这个区间内的和,你怎么求呢?
哇,不会呢!
傻眼,我们肯定是用前30项的和减去前1项的和呀,为什么是前一项不是前2项?因为这里的2,是个开区间,我们要取得.来来来,用我们的语言来表示他,是不是sum=sum[j]-sum[i-1],这里的i和j分别是区间两端的点。
好了,然后题目要求我们算的是,K倍的sum,也就是sum%k==0的情况,再来,sum等于什么?
于是乎,有:sum[j]%k==sum[i-1]%k,这时候我们只要算出,sum[j]和sum[i-1]的情况有多少,是不是就算出答案了呢,来,我们试试看。
1,2,3,4,5 k=2
sum[1]=1 %2过后是 1 dp[sum[1]%k]++
sum[2]=3 %2过后是 1 哇,这个1和前面的1,重复了。对的,这时候我们就要计数了。
count++; count+=dp[sum[2]%k]++
sum[3]=6 %2过后是 0 dp[sum[3]%k]++
sum[4]=10 %2过后是 0 前面的0,重复了,此时我们再一次计数
count++ count+=dp[sum[4]%2]++
sum[5]=15 %2过后是 1 前面的1,重复了2此,我们加两次
count+2;
问题是,怎么用代码实现上述过程?不妨建造一个dp[1]大小的数组,用来存放0和1的个数
我现在用红色的字体,写在上面。看到了吗,算一算,count=4。
????等于4,错的啊,答案等于6啊。的确,因为我们忽略了当区间本身是K的倍数的情况,你看嘛,我们计数的条件是判定有两个相等的区间和,所以区间本身为K的倍数是没有被我们考虑进来的。然后程序就清晰了!
注意事项:
参考代码:
import java.util.Scanner; public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner in=new Scanner(System.in); int n=in.nextInt(); int k=in.nextInt(); int arr[]=new int[n+1]; for(int i=1;i<=n;i++)arr[i]=in.nextInt(); long count=0; int sum[]=new int[n+1]; int dp[]=new int [n+1]; dp[0]=0;//表示第一个数前缀和是多少 for(int i=1;i<=n;i++){ sum[i]=(sum[i-1]+arr[i])%k;//存放前缀和并取模的表 count+=dp[sum[i]];//这句代码要好好理解,dp[sum[i]]是什么意思呢? dp[sum[i]]++; //sum[i]代表前面取模是0或者1,而dp[sum[i]表示前面出现的0的个数和1的个数,出现第一次,我们是不会记录的 } System.out.println(count+dp[0]); } }
0.0分
5 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复