精华内容
下载资源
问答
  • 题意 给定一字符S,定义子串subS[i] = S[0..i],定义C[i]为S中subS[i]数量,求sigma(C[i])(0<=i<...那么我们怎么求出以某个位置为结尾字符中有多少是subS[i]呢? 考虑subS[i]就是...

    题意

    给定一个字符串S,定义子串subS[i] = S[0..i],定义C[i]为S中subS[i]的数量,求sigma(C[i])(0<=i<N)。

    思路

    我们以子串结尾的位置来划分阶段求解,即,设ans[i]表示以第i个字符为结尾的子串的个数,则res = sigma(ans[i])。 那么我们怎么求出以某个位置为结尾的字符串中有多少是subS[i]呢? 考虑subS[i]就是S的N个前缀,而以某个位置为结尾又是后缀,所以我们自然要想到利用next数组---前缀后缀对称来解决这个问题。 由next[i]=j表示S[1...j] = S[i-j+1...i]可知,以i为结尾的子串中包含subS[j]本身,并且,它一定还包含subS[j]所包含的前缀。所以ans[i] = ans[j]+1。 最后再加上以i为结尾的子串它本身(上面计算时并没有包括它本身)。

    代码

      [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; char s[100005]; long long next[100005], res[100005], ans; long long cal_res(int j){ if (next[j] == -1) return 0; else if (~res[j]){ return res[j]; } else{ res[j] = cal_res(next[j]) + 1; return res[j]; } } void get_next(){ int len = strlen(s), j = -1; ans = len; next[0] = -1; for (int i = 1; i < len; i ++){ while(j > -1 && s[i] != s[j+1]) j = next[j]; if (s[i] == s[j+1]) j ++; next[i] = j; ans += cal_res(i); } } int main(){ int t; scanf("%d", &t); while(t --){ MEM(s, 0); MEM(res, -1); scanf("%s", s); get_next(); printf("%lld\n", ans); } return 0; } [/cpp]

    转载于:https://www.cnblogs.com/AbandonZHANG/p/4114333.html

    展开全文
  •  类似数组或者字符串的最大最小问题,往往考虑的一方向是按照每一下标怎么样去考虑,比如:下标为i时,以arr[i]结尾时和为num的最长子串为多少,因为最终的结果一定会以一数组的某个数字结尾所以,所以通过...

           给定一串数组arr,和一个值num,求和为num的最长子串。

           类似数组或者字符串的最大最小问题,往往考虑的一个方向是按照每一个下标怎么样去考虑,比如:下标为i时,以arr[i]结尾时和为num的最长子串为多少,因为最终的结果一定会以一个数组的某个数字结尾所以,所以通过这种方法最后的结果一定在其中。

           接下来来考虑一个具体问题,假如此时要求和为14的最长子串,我在以arr[20]结尾的时候,下标0到20的和为35,那么如果我能确定0下标到多少下标的和为35-14=21(此处假设0到4位置的和为21),那么可以确定5到20这一部分的和一定为14。因为我们要求的是最长的子串,那么我们找的一定是第一次出现和为21的位置,打个比方0到4位置和为21,0到7位置和也未21,那么8到20位置的和也为14,但是显然它比5到20位置要短。

           所以至此,该问题编写流程出来了:

           1、遍历一遍数组,求出对应位置的和;

           2、用一张map,其中key为和,value值为和对应的下标,(注意:map更新时要查询,如果这个和已经存在,因为我们顺序遍历数组,说明先插入map的和位置一定考前,此时不用更新map)

           3、再次遍历数组,这次求每个位置的sum,然后再在map中查询sum-num的值,如果存在,说明以当前位置结尾存在和为num的子串,可以得到一个起始位置和终止位置,然后比较是否比上一次的结果长,长的话就更新,否则不更新。

            至此问题得解,时间复杂度O(n)。

    展开全文
  • 给定字符 A,B,要求从 A 中取出互不重叠 k 非空子,按照出现顺序拼起来后等于 B。方案。n ≤ 1000,m ≤ 200。 主要是状态转移。先设计出$f_{i,j,k}$表长度$B_j$分了$k$段很好想,但是发现并不容易...

    给定字符串 A,B,要求从 A 中取出互不重叠的 k 个非空子串,按照出现顺序拼起来后等于 B。求方案数。n ≤ 1000,m ≤ 200。


    主要是状态的转移。先设计出$f_{i,j,k}$表长度$B_j$分了$k$段很好想,但是发现并不容易转移。

    主要瓶颈在于当枚举了状态$f_{i,j,k}$ 的时候加入可以匹配($A_i=B_j$),怎么从前面$A_1\sim A_{i-1}$里找出$k-1$块的$j-1$的方案数。(注意下面几行都是基于当前$A_i=B_j$这个条件的

    发现这个是可以叠加的,也就是$f_{i,j,k}$可以继承$f_{i-1,j,k}$的所有方案,那么只要不断继承,像滚雪球一样,求$f_{i,j,k}$直接就从$f{i-1,j-1,k-1}$来推就好了。

    第二个问题是,怎么处理拼接。如果枚举一段子串去匹配显然不太可做,发现拼接过程实际就是强制$i-1$处被选入了$k$个块内,然后和$i$位一合并,就完成了拼接。

    于是,为了知道$i-1$强制被选了的情况下有多少种$k$个块的方案,故再添加一维$0/1$表示是否被选。

    这下就可以推了。

    具体可以参见代码(我用了顺推格式)。注意滚动。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define dbg(x) cerr << #x << " = " << x <<endl
     7 using namespace std;
     8 typedef long long ll;
     9 typedef double db;
    10 typedef pair<int,int> pii;
    11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 const int N=1000+5,M=200+5,P=1e9+7;
    21 int f[2][M][M][2],now;
    22 int n,m,l;
    23 char s[N],t[M];
    24 inline void add(int&A,int B){A+=B;A>=P&&(A-=P);}
    25 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    26     read(n),read(m),read(l);
    27     scanf("%s",s+1),scanf("%s",t+1);
    28     f[now=0][0][0][0]=1;
    29     for(register int i=0;i<n;++i,now^=1){
    30         for(register int j=0;j<=m;++j){
    31             for(register int k=0;k<=l;++k){
    32                 add(f[now^1][j][k][0],f[now][j][k][0]),add(f[now^1][j][k][0],f[now][j][k][1]);
    33                 if(s[i+1]==t[j+1])
    34                     add(f[now^1][j+1][k+1][1],f[now][j][k][0]),
    35                     add(f[now^1][j+1][k+1][1],f[now][j][k][1]),
    36                     add(f[now^1][j+1][k][1],f[now][j][k][1]);
    37             //    printf("%d %d %d %d %d\n",i,j,k,f[now][j][k][0],f[now][j][k][1]);
    38                 f[now][j][k][0]=f[now][j][k][1]=0;
    39             }
    40         }
    41     }
    42     printf("%d\n",(f[now][m][l][0]+f[now][m][l][1])%P);
    43     return 0;
    44 }
    View Code

    思路总结:1.继承方案,方便统计。2.子串问题中拼接可以设计0/1状态表示末尾有没有被选,这样可以直接和后面的东西合并

    转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11556205.html

    展开全文
  • 解题报告 NOIP2015 子串

    2017-11-05 16:57:17
    这是一道dp题,然后来想想怎么表示状态,对答案有影响的就是A串的第i字符,B串的第j字符,和k个子串,简单来说就是和选取的字符和子串的数量有关. 那么设 f[i][j][kk]表示在A串的前i字符中选kk个子串匹配B串的...

    这是一道dp题,然后来想想怎么表示状态,对答案有影响的就是A串的第i个字符,B串的第j个字符,和k个子串,简单来说就是和选取的字符和子串的数量有关.
    那么设 f[i][j][kk]表示在A串的前i个字符中选kk个子串匹配B串的前j个字符的方案数.求方案数可以采用加法原理,考虑A串的第i个字符,那么这个字符的决策只有取或不取,很明显,加法原理,把不取的方案数和取的方案数加起来就可以,但是状态的定义并不能看出这个字符到底取不取,或者说并不能推出结果来,怎么办呢?

    那么就用一个数组s[i][j][kk]来表示在A串的前i个字符中选kk个子串匹配B串的前j个字符的方案数,A串的第i个字符会被取到.那么这个s数组该怎么推出来呢?可以发现,如果取第i个字符也有2种可能,因为kk是一定的,第i个字符可能和第i-1个字符合并成一个子串,那么从s[i-1][j][kk]转移过来,也可能不和第i-1个字符合并成一个子串,那么就要新开一个子串,故kk一定从kk-1转移过来,根据加法原理,
    那么s[i][j][kk] = s[i-1][j-1][kk] + f[i-1][j-1][kk-1].

    还有一个问题,f数组该怎么推呢?根据之前分析的,把不取和取的加上来即可,即f[i][j][kk] = s[i][j][kk] + f[i-1][j][kk],其实可以发现,f数组就相当于前缀和数组.

    还有一个问题:这是一个三维的状态转移方程!空间不一定开的下,再看数据范围,这绝对MLE,怎么办?注意到i只能从i或i-1转移过来,可以想到滚动数组,滚动数组有一个比较好些的写法就是把第一维全部加上&1,或者干脆弄两个变量处理完一组数据就交换即可.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int n, m, k;
    
    long long f[2][205][205], s[2][205][205];
    char a[1005], b[205];
    const int mod = 1000000007;
    
    int main()
    {
        scanf("%d%d%d", &n, &m, &k);
        scanf("%s", a + 1);
        scanf("%s", b + 1);
        int now = 1, last = 0;
        f[0][0][0] = 1;
        for (int i = 1; i <= n; i++)
        {
            f[now][0][0] = 1;
            for (int j = 1; j <= m; j++)
                for (int kk = 1; kk <= k; kk++)
                {
                    if (a[i] == b[j])
                        s[now][j][kk] = (s[last][j - 1][kk] + f[last][j - 1][kk - 1]) % mod;
                    else
                        s[now][j][kk] = 0;
                    f[now][j][kk] = (f[last][j][kk] + s[now][j][kk]) % mod;
                }
            swap(now, last); //一定要变,否则就是一直自己跟自己转移.
        }
        printf("%lld\n", f[last][m][k]);
    
        return 0;
    }
    展开全文
  • 由’(‘,’)’组成的字符怎么才能出 来字符S中最长的完美(S的子串)的长度呢?Input输入的第一行是一数字k,代表输入的样例组(k )。 每组样例是一字符只由’(‘,’)’这两字符组成的字符...
  • 字符串处理相关API字符串是7种序列类型中的一种。...如果只是想判断一字符串是不是另一字符串的子串的话,使用序列的in运算符就可以了。例:数数有多少匹配的字符串 - count函数原型:str.count(s...
  • 目录:字符串反转显示回文判断最长回文子串递归字符串替换 replace()字符串分割 split()字符串包含判断 in字符个数统计思路如下:循环对字符串的第一个字符进行替换,替换后长度相减即为第一个字符的出现次数直到...
  • 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来。 首先我们看看 68 分怎么做 ——两个串的本质不同的公共子串个数。...再简化一下:如何一个串的本质不同的子串个数。  给串建一个SA...
  • 后面感觉也挺容易,就是没想到,之前做过SPOJ 694 705求过不同子串了,知道怎么求不同子串个数了,但是比赛时候这个技巧竟然抛在脑后了,然后就不会了。 但是今天自己用了自己两个后缀数组模板(倍增和DC3)...
  • 就是个串的子串的不同子串,这玩意儿冬令营上《字符串前沿算法》讲过。 考虑在把整个串的SAM建出来,注意建的时候记录每结尾点。 然后一把结尾点激活,之所以要先建出来的原因是树的形态就稳固了。 ...
  • cf509e 数学+字符

    2015-11-05 16:50:24
    题目大意:给定一个字符,求任意子串中元音字母I, E, A, O, U, Y所占...接下来就是怎么求所有子串中元音字母个数以及所占比例了。因为当子串长度为i时,必然可以有好多个,simple(i)中分母值一定,分子值相加
  • 给出几由小写字母构成的单词,它们最长的公共子串的长度。... 对于后缀数组而言,多字符串的公共子串与两处理起来并没有什么区别  只要在中间加一些没有用的字符,将多字符串拼成一字符串  ...
  • 题目传送门 题目分析: 这道题就是多个串的不同子串的个数。...所以从每个叶子跑一个SAM,把它们合并起来变成一个大SAM,统计在这个大SAM上不同的子串个数怎么统计? 蒟蒻知道两种方法 : “每...
  • 多个串的不同子串个数? 当然是后缀自动机,最后只要把longest−parent.longestlongest-parent.longest个和就好啦 那么这题怎么建后缀自动机 能够把所有子串都丢进去呢? 当然不用从每一个节点开始 把树建...
  • 你必须知道495C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    3.15 我要检查一个数是不是在另外两个数之间,为什么if(abc)不行? 3.16 为什么如下代码不对?inta=1000,b=1000;longintc=a*b; 3.17 为什么下面代码总是给出0?doubledegC,degF;degC=5.0/9*(degF-32); ...
  • 给你三字符串,第一串的子串 + 第二串的子串 = 第三串的方法有几种 思路: 就是最长公共子序列,f[i][j][k]就代表第一串的前i,第二串的前j,构成第三串前k的方法; 如果第一串的第i和第三串的第k是...
  • 关键是前面怎么求 我们可以考虑枚举一对称轴,那么如果对称轴左右两边有一组对应字符相同,那么当前对称轴答案显然乘上一2,代表这一组是否选择 那么问题变成需要快速求出关于一根轴对称字符对数 对于一...
  • 《你必须知道495C语言问题》

    热门讨论 2010-03-20 16:41:18
    书中列出了C用户经常问400多经典问题,涵盖了初始化、数组、指针、字符、内存分配、库函数、C预处理器等各个方面主题,并分别给出了解答,而且结合代码示例阐明要点。 《你必须知道495C语言问题》结构...
  • 3.15 我要检查一个数是不是在另外两个数之间,为什么if(a b c)不行? 40 3.16 为什么如下代码不对?int a=1000, b=1000; long int c=a * b; 40 3.17 为什么下面代码总是给出0?double degC, degF; degC= ...
  • 书中列出了C用户经常问400多经典问题,涵盖了初始化、数组、指针、字符、内存分配、库函数、C预处理器等各个方面主题,并分别给出了解答,而且结合代码示例阐明要点。 本书结构清晰,讲解透彻,是各高校相关...
  • 书中列出了C用户经常问400多经典问题,涵盖了初始化、数组、指针、字符、内存分配、库函数、C预处理器等各个方面主题,并分别给出了解答,而且结合代码示例阐明要点。  本书结构清晰,讲解透彻,是各高校...
  • 3.15 我要检查一个数是不是在另外两个数之间,为什么if(abc)不行?  3.16 为什么如下代码不对?inta=1000,b=1000;longintc=a*b;  3.17 为什么下面代码总是给出0?doubledegC,degF;degC=5.0/9*(degF-32);  ...
  •  3.15 我要检查一个数是不是在另外两个数之间,为什么if(abc)不行? 3.16 为什么如下代码不对?inta=1000,b=1000;longintc=a*b; 3.17 为什么下面代码总是给出0?doubledegC,degF;degC=5.0/9*(degF-32); ...
  • LOJ#2720 你名字

    2019-01-29 21:10:00
    每个询问是一个t和两个数l,r,表示t中有多少个本质不同的子串没有在s[l,r]中出现过。 解:我写的并不是正解......是个毒瘤做法。只在loj上面卡时过了就写loj的题号好了... 首先有个68分部分分是l = 1, r = |s...

空空如也

空空如也

1 2 3 4 5
收藏数 83
精华内容 33
关键字:

串的子串个数怎么求