Codeforces Round #425 (Div. 2) E-Vasya and Shifts (高斯消元)

E. Vasya and Shifts

    Vasya has a set of 4n strings of equal length, consisting of lowercase English letters "a", "b", "c", "d" and "e". Moreover, the set is split into n groups of 4 equal strings each. Vasya also has one special string a of the same length, consisting of letters "a" only.
    Vasya wants to obtain from string a some fixed string b, in order to do this, he can use the strings from his set in any order. When he uses some string x, each of the letters in string a replaces with the next letter in alphabet as many times as the alphabet position, counting from zero, of the corresponding letter in string x. Within this process the next letter in alphabet after "e" is "a".
    For example, if some letter in a equals "b", and the letter on the same position in x equals "c", then the letter in a becomes equal "d", because "c" is the second alphabet letter, counting from zero. If some letter in a equals "e", and on the same position in x is "d", then the letter in a becomes "c". For example, if the string a equals "abcde", and string x equals "baddc", then a becomes "bbabb".
    A used string disappears, but Vasya can use equal strings several times.
    Vasya wants to know for q given strings b, how many ways there are to obtain from the string a string b using the given set of 4n strings? Two ways are different if the number of strings used from some group of 4 strings is different. Help Vasya compute the answers for these questions modulo 109 + 7.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 500) — the number of groups of four strings in the set, and the length of all strings.

Each of the next n lines contains a string s of length m, consisting of lowercase English letters "a", "b", "c", "d" and "e". This means that there is a group of four strings equal to s.

The next line contains single integer q (1 ≤ q ≤ 300) — the number of strings b Vasya is interested in.

Each of the next q strings contains a string b of length m, consisting of lowercase English letters "a", "b", "c", "d" and "e" — a string Vasya is interested in.

Output

For each string Vasya is interested in print the number of ways to obtain it from string a, modulo 10^9 + 7.

Examples

input
1 1
b
2
a
e
output
1
1

input
2 4
aaaa
bbbb
1
cccc
output
5

Note

In the first example, we have 4 strings "b". Then we have the only way for each string b: select 0 strings "b" to get "a" and select 4 strings "b" to get "e", respectively. So, we have 1 way for each request.

In the second example, note that the choice of the string "aaaa" does not change anything, that is we can choose any amount of it (from 0 to 4, it's 5 different ways) and we have to select the line "bbbb" 2 times, since other variants do not fit. We get that we have 5 ways for the request.

题目大意

n个长度为m的串,每个串最多使用4次,每个串只含a,b,c,d,e。
a等价于0,b等价于1,以此类推,对串加和等价于每个位置单独相加,然后对5取模。
给出q次询问,问用这n个串共有多少种不同的方式得到给出的串。

此题的字母实际就是数字,因此我们很容易构造方程,对字符串的每一位列一个方程,目标串的对应位置就是方程的常数项,每一项前面的系数就等于对应串对应位置的数字,然后x表示这个串的使用次数。因为每一个x不超过4,因此题目等价于在模5意义下求解线性方程组。高斯消元直接上即可。
注意到高斯消元的复杂度是 n3 ,而 qn3 是不能接受的。
注意到每次高斯消元时,方程的左边是一样的,只有常数项不一样,因此我们可以提前将所有串读进来,同时解q个方程组即可。具体可见代码。复杂度 n2(n+q)

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 666
using namespace std;
int n,m,q,G[N][N],R[N][N];
char s[N][N];
ll QM(ll a,ll b,ll c)
{
    a%=c;ll ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%c;
        b>>=1;
        a=a*a%c;
    }
    return ans;
}
void Gauss(int row,int col)
{
    int i,j,k,MR,x,y,ta,tb;
    for(x=1,y=1;x<=row&&y<col;x++,y++)
    {
        MR=x;
        for(i=x+1;i<=row;i++)
        if(abs(G[i][y])>abs(G[MR][y]))MR=i;
        if(MR!=x)
        {
            for(i=1;i<col;i++)swap(G[x][i],G[MR][i]);
            for(i=1;i<=q;i++)swap(R[i][x],R[i][MR]);
        }
        if(!G[x][y]){x--;continue;}
        for(i=x+1;i<=row;i++)
        if(G[i][y])
        {
            ta=G[x][y];tb=G[i][y];
            for(j=y;j<col;j++)G[i][j]=(G[i][j]*ta-G[x][j]*tb)%5;
            for(j=1;j<=q;j++)R[j][i]=(R[j][i]*ta-R[j][x]*tb)%5;
        }
    }
    ll tmp=col-x;bool f;
    if(tmp)tmp=QM(5,tmp,1000000007);
    else tmp=1;
    for(i=1;i<=q;i++)
    {
        f=1;
        for(j=x;j<=row;j++)if(R[i][j]){f=0;break;}
        if(f)printf("%I64d\n",tmp);
        else printf("0\n");
    }
}
int main()
{
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%s",&s[i][1]);
    for(i=1;i<=n;i++)
    for(j=1;j<=m;j++)G[j][i]=s[i][j]-'a';
    scanf("%d",&q);
    for(i=1;i<=q;i++)scanf("%s",&s[i][1]);
    for(i=1;i<=q;i++)
    for(j=1;j<=m;j++)R[i][j]=s[i][j]-'a';
    Gauss(m,n+1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值