• [bzoj 3864]Hero meet devil 题解


    考虑裸的最长公共子序列。

    int n,m,g[20][20];
    char strA[20],strB[20];
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        g[i][j]=max(g[i-1][j],g[i][j-1]);
        g[i][j]=max(g[i][j],g[i-1][j-1]+(strA[i]==strB[j]));
    }
    

    然后大家可能都会做了,就没了,嗯。

    我们可以求满足一种性质的字符串的个数,这种性质可以用 (g[i][j]) 描述。

    (f[i][一个奇怪的东西]) 表示 (g[i][j],1le jle n) 的值为 那个奇怪的东西 的字符串的个数。

    这个 那个奇怪的东西 不好表示,它是一个数组,需要像个办法将它压下来。

    仔细想一想会发现,(g[i][j-1]le g[i][j]le g[i][j-1]+1) 。会发现 (g[i][j]) 的差分数组只有 0 和 1。那么我们可以用一个二进制数存储 这个奇怪的东西。

    那么我们设 (f[i][j]) 表示长度为 (i) 的字符串,和 (S)(g[i][j]) 数组的差分数组为 (j) 的个数。

    我们可以枚举 (i,j) ,枚举后面接的字符转移,转移的时候先将 二进制数 解密成 (g[i][j]),再仿造 最长公共子序列 的方法更新 (g[i][j]),最后再将 (g[i][j]) 加密成 二进制数 就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1000000007;
    int Len,m,End,a[20],ans[20];
    int sum[20],g[20],cnt1[33000];
    int f[1003][33000],to[33000][5];
    char str[20];
    inline int read()
    {
    	int x=0,w=0;char ch=0;
    	while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return w?-x:x;
    }
    int calc(int state,int ch)
    {
    	int temp=0;
    	sum[0]=0;
    	for(int i=0;i<Len;i++)
    	sum[i+1]=sum[i]+(state>>i&1);
    	memset(g,0,sizeof g);
    	for(int i=1;i<=Len;i++){
    		if(a[i]==ch)g[i]=sum[i-1]+1;
    		g[i]=max(g[i],max(sum[i],g[i-1]));
    	}
    	for(int i=0;i<Len;i++)
    	temp+=(g[i+1]-g[i])<<i;
    	return temp;
    }
    int main()
    {
    	int T=read();
    	for(int i=1;i<=32767;i++)
    		cnt1[i]=cnt1[i>>1]+(i&1);
    	while(T --> 0){
    		scanf("%s",str+1);
    		memset(f,0,sizeof f);
    		memset(ans,0,sizeof ans);
    		End=1<<(Len=strlen(str+1));
    		m=read();
    		for(int i=1;i<=Len;i++)
    		if(str[i]=='A')a[i]=1;
    		else if(str[i]=='G')a[i]=2;
    		else if(str[i]=='C')a[i]=3;
    		else a[i]=4;
    		f[0][0]=1;
    		for(int i=0;i<End;i++)
    		for(int j=1;j<=4;j++)
    			to[i][j]=calc(i,j);
    		for(int l=0;l<m;l++)
    		for(int i=0;i<End;i++)
    		for(int c=1;c<=4;c++)
    			(f[l+1][to[i][c]]+=f[l][i])%=mod;
    		for(int i=0;i<End;i++)
    			(ans[cnt1[i]]+=f[m][i])%=mod;
    		for(int i=0;i<=Len;i++)
    			printf("%d
    ",ans[i]);
    	}
    }
    
  • 相关阅读:
    python笔记1
    git笔记
    手撸一个简陋直播系统
    spring-boot学习笔记1
    设计模式1--简单工厂模式
    网联:第一章:浏览器生成消息
    php线上预览日志--4.websocket客户端
    php线上预览日志--3.websocket服务部署
    php线上预览日志--2.谷歌插件开发
    php线上预览日志--1.概述
  • 原文地址:https://www.cnblogs.com/zYzYzYzYz/p/14800436.html
Copyright © 2020-2023  润新知