/*
强力推荐:五星,WA!!!
首先要用到高精度处理。
动态规划的使用这里有点小问题,原来我的想法,d[i][j]表示line1从i和line2从j开始的不同子序列个数。d[i][j]=sum{d[i+1][k] | k属于(j,len2)}。状态有len1*len2种,状态转移有len2种。
另一种解法:d[i][j]=d[i][j+1];if(line1[i]==line2[j]) d[i][j]+=d[i+1][j+1];这样可将状态转移优化为O(1)种。
题意:不同的子序列。字符串line1和line2,求line1的子序列中为line2的个数。
*/
//如果使用递归,使用visit[]来标记是否查找过即可
//#define TEST
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct BigNumber
{
int data[110];
int len;
BigNumber(){len=1;data[0]=0;}
BigNumber(int a){*this=a;}
BigNumber operator=(char a[]);
BigNumber operator=(int a);
BigNumber operator+(BigNumber &a);
friend ostream & operator<<(ostream &out,BigNumber &a);
void clearLeadZero();
};
void BigNumber::clearLeadZero()
{
while(len>0 && data[len]==0)
len--;
}
BigNumber BigNumber::operator=(char a[])
{
len=strlen(a);
for(int i=0;i<len;i++)
data[i]=a[len-1-i]-'0';
return *this;
}
BigNumber BigNumber::operator=(int a)
{
char s[20];
sprintf(s,"%d",a);
*this=s;
return *this;
}
BigNumber BigNumber::operator+(BigNumber &a)
{
int i;
int p=0;
BigNumber c;
for(i=0;p || i<len || i<a.len;i++)
{
if(i<len) p+=data[i];
if(i<a.len) p+=a.data[i];
c.data[i]=p%10;
p/=10;
}
c.len=i;
c.clearLeadZero();
return c;
}
ostream & operator<<(ostream &out,BigNumber &a)
{
for(int i=a.len-1;i>=0;i--)
out<<a.data[i];
return out;
}
const int nMax1=10010,nMax2=110;
BigNumber d[nMax1][nMax2];
char line1[nMax1],line2[nMax2];
int len1,len2;
int N;
void init()
{
gets(line1);
gets(line2);
len1=strlen(line1);
len2=strlen(line2);
for(int i=0;i<=len1;i++)
for(int j=0;j<=len2;j++)
d[i][j]=0;
int p=0;
for(int i=len1-1;i>=0;i--)
{
if(line1[i]==line2[len2-1])
++p;
d[i][len2-1]=p;
#ifdef TEST
cout<<i<<" "<<len2-1<<" "<<d[i][len2-1]<<endl;
#endif
}
}
int main()
{
freopen("f://data.in","r",stdin);
scanf("%d",&N);
getchar();
while(N--)
{
init();
for(int j=len2-2;j>=0;j--)
{
for(int i=len1-(len2-j);i>=0;i--)
{
d[i][j]=d[i+1][j];
if(line1[i]==line2[j])
d[i][j]=d[i][j]+d[i+1][j+1];
#ifdef TEST
cout<<i<<" "<<j<<" "<<d[i][j]<<endl;
#endif
}
}
cout<<d[0][0]<<endl;
}
return 0;
}