ZCC有N个字符串,他正在和Miss G.用这N个字符串玩一个小游戏。ZCC会从这N个串中等概率随机选两个字符串(不可以是同一个)。然后,ZCC和Miss G.轮流操作。Miss G.总是先操作的。在每轮中,操作者可以选择操作A或操作B。 操作A:在两个串中选择一个当前非空的串,然后在这个串的末尾删去一个字符。 操作B: 若当前两个串完全相同且非空,则可以使用这个操作。此时两个串都被清空。 不能操作的玩家输掉了这个游戏。 ZCC想要知道他输掉游戏的概率是多少(也就是Miss G.获胜的概率)。
输入描述
第一行有一个整数 T(T≤5) ,代表测试数据组数。 对于每组数据,第一行有一个非负整数 N(2≤N≤20000) 。接下来的N行中,每行有一个仅由小写字母构成的字符串。保证一组数据中字符串的总长度不超过 200000 .
输出描述
对于每组数据,输出单独的一行代表答案。答案用既约分数"p/q"的形式表示。如果答案是1,输出"1/1";如果答案是0,输出"0/1".
输入样例
1 3 xllendone xllendthree xllendfour
输出样例
2/3
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
#define MAXN 200005
char s[MAXN];
struct Trie
{
int ch[MAXN << 1][26],val[MAXN << 1];
int cnt;
void init()
{
cnt = 1;
memset(ch[0],0,sizeof(ch[0]));
}
int insert(char * s)
{
int u = 0 , len = strlen(s);
for(int i = 0;i < len;i++)
{
if(!ch[u][s[i] - 'a'])
{
memset(ch[cnt],0,sizeof(ch[cnt]));
val[cnt] = 0;
ch[u][s[i] - 'a'] = cnt++;
}
u = ch[u][s[i] - 'a'];
}
return val[u]++;
}
}trie;
LL gcd(LL a,LL b)
{
if(b)return gcd(b,a % b);
else return a;
}
int main()
{
int _,n;
scanf("%d",&_);
while(_--)
{
scanf("%d",&n);
LL ans = 0;
trie.init();
int odd = 0,even = 0;
for(int i = 0;i < n;i++)
{
scanf("%s",s);
int cnt = trie.insert(s);
int len = strlen(s);
if(len & 1)
{
ans += even;
odd++;
}
else
{
ans += odd;
even++;
}
ans += cnt;
}
LL cur = n * (n - 1) / 2;
if(ans == 0)puts("0/1");
else printf("%I64d/%I64d\n",ans / gcd(ans,cur),cur / gcd(ans,cur));
}
}