zoukankan      html  css  js  c++  java
  • 【LOJ#6074】子序列(动态规划)

    【LOJ#6074】子序列(动态规划)

    题面

    LOJ

    题解

    考虑一个暴力(dp)
    (f[i][c])表示当前在第(i)位,并且以(c)结尾的子序列个数。
    那么假设当前位为(a),强制把(a)接在所有出现过的子序列后面,再加上一个单独的(a)
    也就是(f[i][a]=sum_j f[i-1][j]),其他的(f[i][k]=f[i-1][k])
    显然这样一个转移是可以写成矩阵形式的,预处理矩阵的前缀和和矩阵逆的前缀和就可以很方便的计算答案,这样子的复杂度是字符集大小三方的。
    发现我们要的只是一个行向量或者一个列向量。这样子可以优化单次矩乘为字符集大小平方,然而我们直接按照(dp)转移就好了,就变成了字符集大小了。
    那么最终的答案就是一个行向量和一个列向量相乘即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define MOD 1000000007
    #define MAX 100100
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    char s[MAX];
    int n,Q;
    int a[10][10],S[10],L[MAX][10],R[MAX][10];
    int main()
    {
    	scanf("%s",s+1);n=strlen(s+1);Q=read();
    	for(int i=0;i<=9;++i)a[i][i]=S[i]=R[0][i]=1;
    	for(int i=1;i<=n;++i)
    	{
    		int c=s[i]-96,tmp;
    		for(int j=0;j<=9;++j)tmp=a[j][c],a[j][c]=S[j],S[j]=(2ll*S[j]-tmp+MOD)%MOD;
    		for(int j=0;j<=9;++j)R[i][j]=S[j];
    	}
    	memset(a,0,sizeof(a));memset(S,0,sizeof(S));
    	for(int i=0;i<=9;++i)a[i][i]=1,L[0][i]=!i;
    	for(int i=1;i<=n;++i)
    	{
    		int c=s[i]-96,tmp;
    		for(int j=0;j<=9;++j)tmp=(a[c][j]+S[j])%MOD,S[j]=(S[j]-tmp+MOD)%MOD,a[c][j]=(a[c][j]+tmp)%MOD;
    		for(int j=0;j<=9;++j)L[i][j]=(a[0][j]+S[j])%MOD;
    	}
    	while(Q--)
    	{
    		int l=read(),r=read(),ans=MOD-1;
    		for(int i=0;i<=9;++i)ans=(ans+1ll*R[r][i]*L[l-1][i])%MOD;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    编码问题,编码到吐血
    dz验证码
    奇葩之mysql【四】找不到表了
    EntityFramework 使用Mysql数据库
    Create a custom output cache prodiver in asp.net4
    WPF一个很炫的控件
    yield grammar
    最大公约数的故事
    新人
    学习笔记 简单的amob A%B Problem
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10206382.html
Copyright © 2011-2022 走看看