[后缀数组+思路] hdu 4436 str2int

题意:给出n个字符串,求出所有字符串中出现的不同的整数和mod2012的值(即出现多次算一次)

思路:用后缀数组去重的方法很好想到,但是难点在于如何去快速的计算这些不同的子串。

比如两个串

123,124

他们的所有子串

原串:123#124

123#124

124

23#124

24

3#124

4

#124

而答案应是 1+12+123+124+2+23+24+3+4

那么我们该如何计算呢。

假设我们求的字符串 "12345"中的34,我们要怎么快速的求出。
我们定义了两个数组,一个是sum[]表示前缀和,一个是num[]表示数字,比如上面的例子
sum[0] = 1                                                          num[0] = 1 
sum[1] = 1 + 12                                                  num[1] = 12
sum[2] = 1 + 12 + 123                                        num[2] = 123
...                                                                            .....
sum[4] = 1 + 12 + 123 + 1234 + 12345              num[4] = 12345


我们首先将 sum[3] - sum[1] 得到 123 + 1234 , 而我们想要得到是 3 + 34
所以我们要减去 120 和 1200 即 num[1] * 110
用这样的方法就可以快速的求和


具体到我的样例

(1) 没重复     1+12+123=(sum[2]-sum[-1]-(num[-1]*ten[2--1]))-(sum[-1]-sum[-1]-(num[-1]*ten[-1--1]))

(2) 重复2个   124=1+12+124-1-12=(sum[6]-sum[3]-(num[3]*ten[6-3]))-(sum[5]-sum[3]-(num[3]*ten[5-3]))

(3)没重复       2+23=(sum[2]-sum[0]-(num[0]*ten[2-0]))-(sum[0]-sum[0]-(num[0]*ten[0-0]))

(4)重复1个     24=2+24-2=(sum[6]-sum[4]-(num[4]*ten[6-4]))-(sum[5]-sum[4]-(num[4]*ten[5-4]))

依次类推 记得去模就OK了

这里注意下数组下标会是-1 所以可以特判一下 不过其实也没啥 下标是-1的位置值为0

然后还有一个就是注意下  如果当前的前缀开头不是1~9 那么就跳过不计算

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
#define N 120123
int wa[N],wb[N],wv[N],wws[N];
int v[N],ra[N],sa[N],height[N],ten[N];
int num[N],sum[N],length[N];
char fuck[N];
int M=2012;
int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int n,int m)
{
    int i,j,p,*x=wa,*y=wb;
    for(i=0; i<m; i++) wws[i]=0;
    for(i=0; i<n; i++) wws[x[i]=v[i]]++;
    for(i=1; i<m; i++) wws[i]+=wws[i-1];
    for(i=n-1; i>=0; i--) sa[--wws[x[i]]]=i;
    for(j=1,p=1; p<n; j*=2,m=p)
    {
        for(i=n-j,p=0; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0; i<n; i++) wv[i]=x[y[i]];
        for(i=0; i<m; i++) wws[i]=0;
        for(i=0; i<n; i++) wws[wv[i]]++;
        for(i=1; i<m; i++) wws[i]+=wws[i-1];
        for(i=n-1; i>=0; i--) sa[--wws[wv[i]]]=y[i];
        for(swap(x,y),i=1,p=1,x[sa[0]]=0; i<n; i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
    }
    return ;
}
void gethei(int n)
{
    int i,j,k=0;
    for(i=1; i<=n; i++) ra[sa[i]]=i;
    for(i=0; i<n; i++)
    {
        if(k) k--;
        j=sa[ra[i]-1];
        while(v[i+k]==v[j+k]) k++;
        height[ra[i]]=k;
    }
    return ;
}
int main()
{
    int n;
    ten[0]=0;
    for(int i=1;i<=N;i++) ten[i]=((ten[i-1]+1)*10)%M;  //构造0,10,110....数组
    while(scanf("%d",&n)!=-1)
    {
        int len=0;
        int i,j;
        for(i=0; i<n; i++)
        {
            scanf("%s",fuck);
            int l=strlen(fuck);
            int x=0,t=0;
            for(j=0; j<l; j++,len++)
            {
                v[len]=fuck[j];  
                length[len]=l-j;  //标记每段目标位置在哪
                t=t*10+fuck[j]-'0';  //累加求和
                t%=M;
                x+=t;
                x%=M;
                sum[len]=x%M;
                num[len]=t%M;
            }
            sum[len]=num[len]=0;  //分隔符的地方置零
            v[len++]='9'+i+1;    //添加分隔符
        }
        sum[len]=num[len]=0;
        v[len]=0;
        da(len+1,12000);
        gethei(len);
        int ans=0;
        for(i=1; i<=len; i++)  //sa是从1开始的 1~len
        {
            if(v[sa[i]]>='1'&&v[sa[i]]<='9')  //是不是1~9
            {
                int s=sa[i]-1,t1=s+length[sa[i]],t2=s+height[i];  //s为原始位置  t1为目标位置 t2为重复位置如题解所说
                int sum1,sum2;
                if(s<0)  //特判
                {
                    sum1=sum[t1];
                    sum2=sum[t2];
                }
                sum1=sum[t1]-sum[s]-num[s]*ten[t1-s];
                sum2=sum[t2]-sum[s]-num[s]*ten[t2-s];
                ans+=sum1-sum2;
                ans=(ans%M+M)%M;   //防止负数
            }
        }
        printf("%d\n",ans%M);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值