相似字符串

http://msbop.openjudge.cn/bop2013/R1a_B/

比较基础的卷积题目,从卷积的定义来看,例如f(x1)和g(x2)的卷积,就是把g(x2)以y轴翻转然后在左移x3个单位,然后俩个函数相乘再在定义域上积分(离散的是求和),x3就是卷积得到函数的自变量,离散的卷积就相当于多项式的乘法。顺便存一下模板。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#include <bitset>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
typedef LL TY;
typedef long double LF;

const int MAXN(140010);
const int MAXM(100010);
const int MAXE(100010);
const int MAXK(6);
const int HSIZE(131313);
const int SIGMA_SIZE(26);
const int MAXH(19);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);
const LL MOD(1000000007);
const double EPS(1e-7);
const LF PI(acos(-1.0));

template<typename T> void checkmax(T &a, T b){if(b > a) a = b;}
template<typename T> void checkmin(T &a, T b){if(b < a) a = b;}
template<typename T> T ABS(const T &a){return a < 0? -a: a;}

struct COMPLEX
{
	double a, b;
	COMPLEX(double a_, double b_): a(a_), b(b_){}
	COMPLEX(){}
	friend COMPLEX operator +(const COMPLEX &op1, const COMPLEX &op2){ return COMPLEX(op1.a+op2.a, op1.b+op2.b);}
	friend COMPLEX operator -(const COMPLEX &op1, const COMPLEX &op2){ return COMPLEX(op1.a-op2.a, op1.b-op2.b);}
	friend COMPLEX operator *(const COMPLEX &op1, const COMPLEX &op2){ return COMPLEX(op1.a*op2.a-op1.b*op2.b, op1.a*op2.b+op1.b*op2.a);}
};

void change(COMPLEX *y, int len)
{
	for(int i = 1, j = len/2; i < len-1; ++i)
	{
		if(i < j) swap(y[i], y[j]);
		int k = len/2;
		while(j >= k)
		{
			j -= k;
			k /= 2;
		}
		if(j < k) j += k;
	}
}

double rc[20], rs[20];

double COS(int h){return h < 0? rc[-h]: rc[h];}  //预处理出cos和sin值
double SIN(int h){return h < 0? -rs[-h]: rs[h];}

void FFT(COMPLEX *y, int len, int flag)
{
	change(y, len);
	for(int h = 2, t = 1; h <= len; h <<= 1, ++t)
	{
		COMPLEX wn(COS(flag*t), SIN(flag*t));
		for(int j = 0; j < len; j += h)
		{
			COMPLEX w(1, 0);
			int temp = h >> 1;
			for(int k = j; k < j+temp; ++k)
			{
				COMPLEX u = y[k];
				COMPLEX t = w*y[k+temp];
				y[k] = u+t;
				y[k+temp] = u-t;
				w = w*wn;
			}
		}
	}
	if(flag == -1)
		for(int i = 0; i < len; ++i)
			y[i].a /= len;
}

COMPLEX arr[2][10][MAXN];
char str1[50010], str2[50010];
int rec[50010];

int main()
{
	for(int i = 1; i <= 17; ++i)
	{
		rc[i] = cos(PI*2/(1 << i));
		rs[i] = sin(PI*2/(1 << i));
	}
	int TC, n_case(0);
	scanf("%d", &TC);
	while(TC--)
	{
		scanf("%s%s", str2, str1);
		int len1 = strlen(str1), len2 = strlen(str2);
		int l = 0, r = len2-1;
		while(l < r)
			swap(str2[l++], str2[r--]);
		int temp = len2*2;
		l = 1;
		while(l < temp) l <<= 1;
		for(int i = 0; i < l; ++i)
			for(int j = 0; j < 10; ++j)
				arr[0][j][i] = arr[1][j][i] = COMPLEX(0, 0);
		for(int i = 0; i < len1; ++i)
			arr[0][str1[i]-'0'][i] = COMPLEX(1, 0);
		for(int i = 0; i < len2; ++i)
			arr[1][str2[i]-'0'][i] = COMPLEX(1, 0);
		for(int i = 0; i <= len2; ++i)
			rec[i] = 0;
		for(int i = 0; i < 10; ++i)
		{
			FFT(arr[0][i], l, 1);
			FFT(arr[1][i], l, 1);
			for(int j = 0; j < l; ++j)
				arr[0][i][j] = arr[0][i][j]*arr[1][i][j];
			FFT(arr[0][i], l, -1);
			for(int j = len1-1; j < len2; ++j)
				rec[j] += (int)(arr[0][i][j].a+0.5);
		}
		int ans = 0;
		for(int i = len1-1; i < len2; ++i)
			checkmax(ans, rec[i]);
		printf("Case #%d: %d\n", ++n_case, len1-ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值