码迷,mamicode.com
首页 > 其他好文 > 详细

整除k的最大连续子区间(前缀和取模)(2017美团笔试)

时间:2017-09-01 15:02:26      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:笔试   style   res   美团   space   play   cst   ==   logs   

题意:一个数n,给出n个数,再给一个数k。求能整除k的连续区间和所在区间的最大长度。bc85场1001的升级版。

题解:刚拿到题的时候没看清是连续区间,就瞎想dp。发现连续区间后,想尺取法,发现这道题是离散的,没法尺取,也没法二分。

           正解应该是前缀和取模。若(sum[j]-sum[i])%k==0则区间[i,j]的和是能整除k的。注意,前缀和的第一项是0。

           预处理完成后,考虑如何求最大区间长。从前往后扫一次,记录每个值最早出现的位置。从后往前扫一次,以便记录每个值最后出现的位置。当值为0时,则记录出现的最后位置,从第一个数到该位置的区间和一定能整除k。

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k,cnt;
int a[500100],sum[500100],ans[500100];
int temp[500010];
int b[500100],c[500100],d[500100];
int main(){
   while(scanf("%d",&n)!=EOF){
      memset(sum,0,sizeof(sum));
      memset(ans,0,sizeof(ans));
      for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i]; //前缀和
      }
      scanf("%d",&k);
      cnt=0;
      memset(temp,0,sizeof(temp));
      for(int i=1;i<=n;i++){
        ans[i]=sum[i]%k;     //前缀和取模 
        if(temp[ans[i]]==0){
            temp[ans[i]]++;
            b[ans[i]]=i;
            d[cnt++]=ans[i]; //保存值的种类
        }
        //printf("%d ",ans[i]);
      }//printf("\n");
      int res;
      memset(temp,0,sizeof(temp));
      for(int i=n;i>=1;i--){
        if(temp[ans[i]]==0){
            if(ans[i]==0){
                res=i;   //最远距离初始化为最后一个0的位置
            }
            temp[ans[i]]++;
            c[ans[i]]=i;
        }
      }
      for(int i=0;i<cnt;i++){
        //printf("tt: %d %d %d\n",d[i],b[d[i]],c[d[i]]);
        if(d[i]!=0){
            res=max(res,c[d[i]]-b[d[i]]);
        }
      }
      printf("%d\n",res);
   }
   return 0;
}
View Code

 

整除k的最大连续子区间(前缀和取模)(2017美团笔试)

标签:笔试   style   res   美团   space   play   cst   ==   logs   

原文地址:http://www.cnblogs.com/dominating/p/7463176.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!