• 题解 Hero meet devil


    题目传送门

    题目大意

    给出一个长度为 (n) 的字符串,对于每个 (kin [0,n]),求出有多少个长度为 (m) 的字符串满足两者最长公共子序列长度为 (k)

    (nle 15,mle 10^3),答案对 (10^9+7) 取模。

    思路

    难得扣shi。。。

    首先,我们发现如果对两个已知字符串求最长公共子序列,那么我们可以设 (f_{i,j}) 表示第 1 个字符串匹配到 (i),第 2 个字符串匹配到 (j) 的最长匹配长度。不难得到转移式:

    [f_{i,j}=f_{i-1,j-1}+1{a_i=b_j} ]

    [f_{i,j}=max{f_{i-1,j},f_{i,j-1}} ]

    于是你发现我们一个字符串其实并不需要知道每一位,我们只需要知道 (f_{i,j}) 即可。但是你发现你不好把这个压进状态里面,但是你发现对于每一个 (i)(j) 每变化 (1) 位答案最多只会增加 (1),于是你可以考虑把每一位的增加量存进状态里面,这样你就可以做到 (Theta(2^nm))了。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXM 1005
    #define MAXN 15
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    char s[MAXN];
    int n,m,ans[MAXN],dp[1 << MAXN][MAXM];
    void Add (int &a,int b){a = a + b >= mod ? a + b - mod : a + b;} 
    
    int a[MAXN],b[MAXN],trans[1 << MAXN][4];
    
    int getid (char c){return c == 'A' ? 0 : (c == 'T' ? 1 : (c == 'C' ? 2 : 3));}
    
    void init (){
    	for (Int S = 0;S < 1 << n;++ S){
    		for (Int i = 1;i <= n;++ i) a[i] = a[i - 1] + (S >> i - 1 & 1);
    		for (Int i = 0;i < 4;++ i){
    			for (Int j = 1;j <= n;++ j)
    				if (getid (s[j]) == i) b[j] = a[j - 1] + 1;
    				else b[j] = max (b[j - 1],a[j]);
    			trans[S][i] = 0;
    			for (Int j = 1;j <= n;++ j) trans[S][i] |= b[j] - b[j - 1] << j - 1; 
    		}
    	}
    }
    
    int popcount (int S){
    	int res = 0;for (Int i = 0;i < n;++ i) res += S >> i & 1;
    	return res;
    }
    
    signed main(){
    	int t;read (t);
    	while (t --> 0){
    		scanf ("%s",s + 1),read (m);
    		n = strlen (s + 1),init ();
    		memset (dp,0,sizeof (dp)),dp[0][0] = 1;
    		for (Int i = 0;i < m;++ i)
    			for (Int S = 0;S < 1 << n;++ S)
    				for (Int j = 0;j < 4;++ j)
    					Add (dp[trans[S][j]][i + 1],dp[S][i]);
    		for (Int i = 0;i <= n;++ i) ans[i] = 0;
    		for (Int S = 0;S < 1 << n;++ S) Add (ans[popcount (S)],dp[S][m]);
    		for (Int i = 0;i <= n;++ i) write (ans[i]),putchar ('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    JSP数据交互(一)
    response.setHeader()用法
    Vue初步认识
    Socket初步了解
    DOM4j的修改删除方式
    多线程
    ArrayList和Vector区别
    集合框架(一)
    深入C#数据类型
    深入.NET框架
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13706679.html
Copyright © 2020-2023  润新知