Hasan is a computer science student, he likes his study field, especially programming and algorithms, but he doesn’t like attending classes at all since they are very boring, especially that the quality of education in his college is extremely low, but sometimes he is forced to attend in order to maintain his attendance rate otherwise he will be prevented from doing final exams!
Currently Hasan is attending `communication skills` class and he is now feeling very bored especially that he thinks such course should not belong to a computer science program, luckily he remembered a problem that one of his friends has given him so he decided to spend the time thinking about it, the problem states:
Given a string S of length N of lower English letters, find how many strings T exists of length N of lower English letters such that T is palindrome and hamming distance between T and S is at most K. since the answer is large find the remainder modulo 109 + 7
Since you also don’t like `communication skills` classes you decided to solve this problem too.
Input
The first line of the input contains an integer T denoting the number of test cases.
each test-case is described with two lines, the first line of each test-case contains two integers N and K.
The second line of each test-case will contains the string S of length N.
Output
For each test case, output a single line containing the answer to the test-case.
Constraints
- 1 ≤ T ≤ 10,000
- 1 ≤ N ≤ 300,000
- 1 ≤ sum of N in all test-cases ≤ 1,000,000
- 0 ≤ K ≤ N
- String S will consist of English lower letters.
Example
Input: 2 3 2 abc 3 1 abc Output: 76 2
Explanation
in second test-case the only possible strings are "aba" and "cbc"
题意:给一个字符串,要求修改至多K个字符使它变成回文串,问方案数。
思路:对称的字符数有Fix个,不对称的有UnFix个。显然Fix那些一修改就要修改两个,这就可以先预处理Fix那些方案数,Fixed[i]表示至多修改i个Fix字符令其是对称的方案数。UnFix里面,每对字符要么修改其中一个,要么两个都修改,那么我们枚举只修改一个的,那么其余的两个都要修改的数量立刻可以求出来,具体见代码。 这种题一般都要固定某些枚举值,找到这些可以枚举的变量就行了。
# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 3e5+3;
const LL mod = 1e9+7;
char s[maxn];
LL inv[maxn+3]={1,1}, fac[maxn+3]={1,1}, fi[maxn+3]={1,1};
LL f25[maxn]={1,25}, f24[maxn]={1,24}, f2[maxn]={1,2};
LL Fixed[maxn];
void init()
{
for(int i=2; i<=maxn-3; ++i)
{
f25[i] = f25[i-1]*25%mod;
f24[i] = f24[i-1]*24%mod;
f2[i] = f2[i-1]*2%mod;
fac[i] = fac[i-1]*i%mod;
inv[i] = (mod-mod/i)*inv[mod%i]%mod;
fi[i] = fi[i-1]*inv[i]%mod;
}
}
LL C(LL n, LL m)//求组合数
{
if(n<m) return 0;
return fac[n]*fi[m]%mod*fi[n-m]%mod;
}
LL solve(int k, LL fix, LL unfix)
{
LL ans = 0;
Fixed[0] = 1LL;
for(int i=1; i<=k; ++i)//预处理fix那些
{
Fixed[i] = Fixed[i-1];
if(i%2==0) Fixed[i] = (Fixed[i] + C(fix, (LL)i/2)*f25[i/2]%mod)%mod;
}
for(int i=0; i<=k && i<=unfix; ++i)//unfix那些
{
int r = i+(unfix-i)*2;
if(r <= k)
{
LL tmp = C(unfix, (LL)i)*f2[i]%mod;//2^i的意思是这i对字符,每对各有两种修改方案。
tmp = tmp*f24[unfix-i]%mod;//24^(unfix-i)的意思是其余的unfix对字符,各有24种修改方案。
ans = (ans + tmp*Fixed[k-r]%mod)%mod;//剩余的修改名额分配给fix那些。
}
}
return ans;
}
int main()
{
init();
int T, n, k;
LL fix, unfix;
scanf("%d",&T);
while(T--)
{
fix = unfix = 0;
scanf("%d%d",&n,&k);
scanf("%s",s);
for(int i=0; i<n/2; ++i)
{
if(s[i] != s[n-i-1]) ++unfix;
else ++fix;
}
if(n&1)//奇数长度时中间那个字符另外讨论。
{
LL ans = solve(k, fix, unfix);
ans = (ans + solve(k-1, fix, unfix)*25%mod)%mod;
printf("%lld\n",ans);
}
else
printf("%lld\n",solve(k, fix, unfix));
}
return 0;
}