1733.ranking

題目描述

小x有n個小姊妹(根據典故,我們假設n≤3000)。他每天都喜歡按不同標準給小姊妹們排(da)序(fen)。今天,他突然對小姊妹們的名字產生了興趣。他覺得小姊妹的魅力和她們的名字有密切聯繫,於是他覺得所有有相似的名字的小姊妹必須排在一起。

相似是指,名字的開頭一個或若干個連續字母相同。於是,小x定下了如下規則:在任何以同樣的字母序列開頭的名字之間,所有名字開頭必須是同樣的字母序列。

比如,像MARTHA和MARY這兩個名字,它們都以MAR開頭,所以像MARCO或MARVIN這樣的名字可以插入這兩個名字中間,而像MAY這樣的就不行。
顯然,按字典序排序是一個合法的排序方案,但它不是唯一的方案。你的任務就是計算出所有合法的方案數。考慮到答案可能很大,輸出答案 mod 1 000 000 007。

輸入

第一行一個整數n,小x的小姊妹個數。
第2~n+1行,每行一個字符串,代表這個小姊妹的名字。

輸出

一行一個整數,合法的方案數。

數據範圍限制

對於60%的數據:3 ≤ n ≤ 10。

對於100%的數據:3 ≤ n ≤ 3000,1 ≤ 字符串長度 ≤ 3000,並且只含有大寫字母。

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int n;
long long fac[3010];
long long ans;
string a[3010];
const int mod = 1e9 + 7;
long long factor(int k)
{
	if(k == 0)
		return 0;
	if(fac[k])
		return fac[k];
	fac[k] = (factor(k - 1) * k) % mod;
	return fac[k];
}
long long dg(int k,int beg,int len)
{
	if(len == 1)
		return 1;
	int buc[30];
	int begin[30];
	int count = 0;
	memset(buc,0,sizeof buc);
	memset(begin,0,sizeof begin);
	long long ret = 1;
	for(register int i = beg + len - 1;i >= beg;--i)
	{
		if(k >= a[i].length())
		{
			++buc[0],begin[0] = i;
			continue;
		}
		++buc[a[i][k] - 'A' + 1],begin[a[i][k] - 'A' + 1] = i;
	}
	for(register int i = 0;i <= 26;++i)
		if(buc[i])
			ret = (ret * dg(k + 1,begin[i],buc[i])) % mod,++count;
	return (ret * factor(count)) % mod;
}
int main()
{
	freopen("ranking.in","r",stdin);
	freopen("ranking.out","w",stdout);
	scanf("%d",&n);
	fac[1] = 1;
	for(register int i = 1;i <= n;++i)
		cin >> a[i];
	sort(a + 1,a + n + 1);
	ans = dg(0,1,n);
	printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章