HDU 5482(思路题目)

对于一个串来说我们粗略的看,它有多少个子串只和它各个位置的相等关系有关,所以我们没必要在乎字符集有多大,只需要枚举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;
}

你可能感兴趣的:(HDU 5482(思路题目))