codeforces1111d(dp、组合数学)

D. Destroy the Colony

time limit per test

2 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

There is a colony of villains with several holes aligned in a row, where each hole contains exactly one villain.

Each colony arrangement can be expressed as a string of even length, where the ii-th character of the string represents the type of villain in the ii-th hole.

Iron Man can destroy a colony only if the colony arrangement is such that all villains of a certain type either live in the first half of the colony or in the second half of the colony.

His assistant Jarvis has a special power. It can swap villains of any two holes, i.e. swap any two characters in the string; he can do this operation any number of times.

Now Iron Man asks Jarvis qq questions. In each question, he gives Jarvis two numbers xx and yy. Jarvis has to tell Iron Man the number of distinct colony arrangements he can create from the original one using his powers such that all villains having the same type as those originally living in xx-th hole or yy-th hole live in the same half and the Iron Man can destroy that colony arrangement.

Two colony arrangements are considered to be different if there exists a hole such that different types of villains are present in that hole in the arrangements.

Input

The first line contains a string ss (2≤|s|≤1052≤|s|≤105), representing the initial colony arrangement. String ss can have both lowercase and uppercase English letters and its length is even.

The second line contains a single integer qq (1≤q≤1051≤q≤105) — the number of questions.

The ii-th of the next qq lines contains two integers xixi and yiyi (1≤xi,yi≤|s|1≤xi,yi≤|s|, xi≠yixi≠yi) — the two numbers given to the Jarvis for the ii-th question.

Output

For each question output the number of arrangements possible modulo 109+7109+7.

Examples

input

Copy

abba
2
1 4
1 2

output

Copy

2
0

input

Copy

AAaa
2
1 2
1 3

output

Copy

2
0

input

Copy

abcd
1
1 3

output

Copy

8

Note

Consider the first example. For the first question, the possible arrangements are "aabb" and "bbaa", and for the second question, index 11 contains 'a' and index 22 contains 'b' and there is no valid arrangement in which all 'a' and 'b' are in the same half.

题目链接:http://codeforces.com/problemset/problem/1111/D

题意:一串包含大小写字母的串(长度为偶数),现在有q次询问,每次给出x,y表示串中对应位置的字符(假设为a、b),现在要求所有a、b同在串的前半段或者后半段,其余相同的字符要在串前半段或者后半段。

思路:dp+组合数学。

虽然询问次数为1e5,但是实际上选出来两个字符的种类数只有52X52种(注意到这点就比较好做了)。首先在len/2中选出位置放置两种字符,然后再安排其余的字符。我们可以dp出由这些字符来组成的所有长度的方案数(不考虑顺序,相当于集合)即01背包,然后再面对不同的a、b时只需要在原基础上减去这两个字符的情况就可以。我们可以求出没有a、b的组成长度为len/2的方案数。现在这些是集合状态,要把他们化成有顺序的串用到排列公式。注意到所有的方案中其排列的种数还是一样的,因为分母一样、分子也一样,这点很容易的得到。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
const ll mod = 1e9+7;
char s[maxn];  //input string
int num[55];   //element cnt
ll dp[maxn];
ll tmp[maxn];
ll quesnum[55][55];
ll ques[55][55];
ll inv[maxn],fac[maxn],invf[maxn];   //inv[i]为i的逆元,fac[i]为阶乘i!,invf[i]为阶乘i!的逆元
void init(int hf)
{
    inv[1]=1;  
    for (int i=2;i<maxn;i++)  
        inv[i]=((mod-mod/i)*inv[mod%i])%mod; 
    fac[0] = 1; 
    for(int i = 1;i<maxn;i++)
        fac[i] = (fac[i-1] * (ll)i)%mod;
    invf[0] = 1;
    for(int i = 1;i<maxn;i++)
        invf[i] = (invf[i-1]*inv[i])%mod;
    
    memset(dp,0,sizeof(dp));
    memset(ques,-1,sizeof(ques));
    dp[0] = 1;
    for(int i =0;i<55;i++)
    {
        if(!num[i])continue;
        for(int j = hf;j>=num[i];j--)
        {
            dp[j] = (dp[j] + dp[j - num[i]])%mod;
        }
    }
    for(int i = 0;i<52;i++)
    {
        for(int j = i;j<52;j++)
        {
            for(int k = 0;k<=hf;k++)tmp[k] = dp[k];
            for(int k = num[i];k<=hf;k++)tmp[k] = (tmp[k] - tmp[k-num[i]] + mod)%mod;
            if(i!=j)
                for(int k = num[j];k<=hf;k++)tmp[k] = (tmp[k] - tmp[k-num[j]] + mod)%mod;
            quesnum[i][j] = quesnum[j][i] = tmp[hf];
        }
    }
}
int main()
{
    
    scanf("%s",s);
    memset(num,0,sizeof(num));
    int len = strlen(s);
    int hf = len/2;
    for(int i = 0;i<len;i++)
    {
        if(s[i]>='a'&&s[i]<='z')num[s[i] - 'a']++;
        else num[s[i] - 'A' + 26]++;
    }
    init(hf);
    int q;
    scanf("%d",&q);
    int x,y;
    while(q--)
    {
        scanf("%d%d",&x,&y);
        x--;y--;
        int idx,idy;
        if(s[x]>='a'&&s[x]<='z')idx = s[x] - 'a';
        else idx = s[x] - 'A' + 26;
        if(s[y]>='a'&&s[y]<='z')idy = s[y] - 'a';
        else idy = s[y] - 'A' + 26;
        if(ques[idx][idy]!=-1)
        {
            printf("%I64d\n",ques[idx][idy]);
            continue;
        }
        ll ans;
        if(idx == idy)
        {
            if(num[idx]>hf)
            {
                printf("0\n");
                ques[idx][idx] = 0;
                continue;
            }
            ll cc = ((fac[hf] * invf[num[idx]] )%mod* invf[hf - num[idx]])%mod;
            ans = ((cc * fac[hf - num[idx]])%mod * fac[hf])%mod;
        }
        else
        {
            if(num[idx] + num[idy]>hf)
            {
                ques[idx][idy] = ques[idy][idx] = 0;
                printf("0\n");
                continue;
            }
            int numx = num[idx],numy = num[idy];
            int num_hfx = hf - numx;
            ll cc1 = ((fac[hf] * invf[numx] )%mod* invf[hf - numx])%mod;
            ll cc2 = ((fac[num_hfx] * invf[numy] )%mod* invf[num_hfx - numy])%mod;
            ans = (((cc1 * cc2)%mod * fac[hf])%mod * fac[hf - numx - numy])%mod;
        }
        for(int i = 0;i<55;i++)
        {
            if(i==idx || i == idy)continue;
            ans = (ans * invf[num[i]])%mod;
        }
        ans = (ans * quesnum[idx][idy])%mod;
        ans = (ans * 2)%mod;
        ques[idx][idy] = ques[idy][idx] = ans;
        printf("%I64d\n",ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值