HDOJ 4648 Magic Pen 6(暴力,DP,哈希表简单)

来源:互联网 发布:多益网络找回 编辑:程序博客网 时间:2024/05/16 19:14

Magic Pen 6

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 2054    Accepted Submission(s): 704



Problem Description
In HIT, many people have a magic pen. Lilu0355 has a magic pen, darkgt has a magic pen, discover has a magic pen. Recently, Timer also got a magic pen from seniors.

At the end of this term, teacher gives Timer a job to deliver the list of N students who fail the course to dean's office. Most of these students are Timer's friends, and Timer doesn't want to see them fail the course. So, Timer decides to use his magic pen to scratch out consecutive names as much as possible. However, teacher has already calculated the sum of all students' scores module M. Then in order not to let the teacher find anything strange, Timer should keep the sum of the rest of students' scores module M the same.

Plans can never keep pace with changes, Timer is too busy to do this job. Therefore, he turns to you. He needs you to program to "save" these students as much as possible.
 

Input
There are multiple test cases.
The first line of each case contains two integer N and M, (0< N <= 100000, 0 < M < 10000),then followed by a line consists of N integers a1,a2,...an (-100000000 <= a1,a2,...an <= 100000000) denoting the score of each student.(Strange score? Yes, in great HIT, everything is possible)
 

Output
For each test case, output the largest number of students you can scratch out.
 

Sample Input
2 31 63 32 3 62 51 3
 

Sample Output
120
Hint
The magic pen can be used only once to scratch out consecutive students.
 
 
这道题也解得听坎坷,看略懂学长博客,居然打了个水题标签哭无爱。。。。
 
题目的意思是给出一个长度为n的数列,问最多可以划掉一个多长的数列能使原数列和现数列对m取余的结果相等。
 
 
法1:暴力。(同样是枚举,我的就超时了,振宇的就过了,智商压制啊。人艰不拆哭
 
解题思路:找出最长连续子序列使它们之和能被m整除。
 
代码如下:
 
#include<stdio.h>#define max 100010int sum[max];int main(){int n,m,i,j,a,sign,len;sum[0]=0;while(scanf("%d%d",&n,&m)!=EOF){for(i=1;i<=n;i++){sum[i]=0;scanf("%d",&a);sum[i]=sum[i-1]+a; }sign=0;//记录是否找到相关数列 len=0;for(i=n;i>=1;i--)//从数列两端开始遍历,找出最长被m整除数列 {for(j=1;j+i-1<=n;j++){if((sum[j+i-1]-sum[j-1])%m==0){len=i;sign=1;break;//找到能被m整除 的序列就能马上跳出遍历,因为每次遍历序列长度都会缩短 }}if(sign)   break;}printf("%d\n",len);}return 0;} 

 
法2:DP
 
 
解题思路:利用hash表记录 前i项和 第一次出现某余数的位置,如果这个余数出现过,则可以去除掉 (我们要去掉m的倍数),然后取最长的就可以了。
 
代码如下:
 
#include<stdio.h>#include<string.h>#define max 100010int a[max],hs[max];int main(){int n,m,i,len;while(scanf("%d%d",&n,&m)!=EOF){memset(hs,-1,sizeof(hs));memset(a,0,sizeof(a));for(i=1;i<=n;i++)    scanf("%d",&a[i]);len=0;hs[0]=0;//注意当余数为零时可以直接把长度当成目标数列的长度 for(i=1;i<=n;i++){a[i]+=a[i-1];a[i]%=m;if(a[i]<0)//c语言中 -3%5 = -3 , 但是题目要求应该是 2。    a[i]+=m;if(hs[a[i]]!=-1)//找到一个相同余数的更长序列,减去上一个序列的位置 {if(i-hs[a[i]]>len)   len=i-hs[a[i]];}elsehs[a[i]]=i;//利用哈希表记录余数出现的位置 }printf("%d\n",len);}return 0;}

 
 
0 0
原创粉丝点击