程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Light OJ 1334 Genes in DNA KMP+DP

Light OJ 1334 Genes in DNA KMP+DP

編輯:C++入門知識

題目來源:Light OJ 1334 Genes in DNA

題意:輸入文本串和模式串 模式串的前綴和後綴組成(n-1)*(n-1)個組合 求模式串的子串出現多少次前後綴組合 一個子串可以對應多個組合串

思路:既然是前綴和後綴的組合 很好想到正反求2次KMP 枚舉相鄰的2個字符 i,j 答案就是若干以i結尾的前綴數量乘以j為開始的後綴數量的積的和

求到i字符為止的前綴數量和HDU 3336差不多 有點DP的思想

求以j字符開始的後綴數就是發過來 然後和求前綴一樣的

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 50010;
int l[maxn], r[maxn], f[maxn];
int dp1[maxn], dp2[maxn];
char s1[maxn], s2[maxn];
void getFail(char *p, int *dp)
{
	int m = strlen(p);
	f[0] = f[1] = 0;
	dp[0] = 0;
	dp[1] = 1;
	for(int i = 1; i < m; i++)
	{
		int j = f[i];
		while(j && p[i] != p[j])
			j = f[j];
		f[i+1] = p[i] == p[j] ? j+1 : 0;
		dp[i+1] = p[i] == p[j] ? dp[j+1]+1 : 1;
	}
}
void find(char *s1, char* s2, int* dp, int* a)
{
	int cnt = 0;
	int j = 0;
	int n = strlen(s1);
	int m = strlen(s2);
	for(int i = 0; i < n; i++)
	{
		while(j && s1[i] != s2[j])
			j = f[j];
		if(s1[i] == s2[j])
			j++;
		a[i+1] = dp[j];
		if(j == m)
		{
			a[i+1]--;
			j = f[j];
		} 
	}
}


int main()
{
	int cas = 1;
	int T;
	scanf("%d", &T);
	while(T--)
	{
		
		scanf("%s %s", s1, s2);
		int n = strlen(s1);
		int m = strlen(s2);
		getFail(s2, dp1);
		find(s1, s2, dp1, l);
		reverse(s1, s1+n);
		reverse(s2, s2+m);
		getFail(s2, dp2);
		find(s1, s2, dp2, r);
		long long ans = 0;
		for(int i = 1; i < n; i++)
		{
			ans += (long long)l[i]*r[n-i];
		}
		printf("Case %d: %lld\n", cas++, ans);
	}
	return 0;
}




  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved