对于一个串来说我们粗略的看,它有多少个子串只和它各个位置的相等关系有关,所以我们没必要在乎字符集有多大,只需要枚举n的所有划分,处理出cnt[i][j][k]cnt[i][j][k]cnt[i][j][k]表示长度为iii的串有jjj个不同的字符且有kkk个子串的方案,每一次枚举的时候要么后面加一个已经出现过的字符,要么加一个新的字符。这样搜索状态总数只有BellnBell_nBelln个,对于n=10n=10n=10绰绰有余。
对于每次询问,只需要枚举一下这个串有多少个不同的字符,然后组合数统计即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define rep1(i,x,y) for(int i=x;i<=y;i++) typedef long long ll; typedef unsigned long long llu; const int base = 123; const int N = 110; const int mod = 1e9 + 7; int ans[N] ; llu tem[N]; ll a[11][11][N]={0}; void cal(int n,int co){ int cnt = 0; rep1(i,1,n) { llu ha = 0; rep1(j,i,n) ha = ha*base+ans[j]+'a',tem[cnt++]=ha; } sort(tem,tem+cnt); cnt = unique(tem,tem+cnt)-tem; a[n][co][cnt]++; } void dfs(int p,int c){ rep1(i, 1 , c){ ans[p] = i; cal(p,max(i,c-1)); if(p < 10) dfs(p+1,max(i+1,c)); } } int n,m,k; ll c[N]; void init(){ c[0]=1; rep1(i,1,min(n,k)) c[i] = c[i-1]*(k-i+1)%mod; } int main() { dfs(1 , 1); int T; scanf("%d",&T); while(T--){ scanf("%d %d %d",&n,&m,&k); init(); ll an = 0; rep1(i,1,n){ an = (an + (ll)a[n][i][m]*c[i]%mod)%mod; } printf("%d\n",(int)an); } return 0; }