题意:给你一个字符串,问你含有 k个字符集合 长度最短的不是字符串子序列的种类数和长度。
解题思路:DP.很难想 site[i] 表示以i 开头的使得 串不再字符串中的最小长度 ,dp[i] 表示种类数。 状态转移方程在代码里面。
解题代码:
1 // File Name: j.4.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月20日 星期五 16时43分43秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque> 10 #include<stack> 11 #include<bitset> 12 #include<algorithm> 13 #include<functional> 14 #include<numeric> 15 #include<utility> 16 #include<sstream> 17 #include<iostream> 18 #include<iomanip> 19 #include<cstdio> 20 #include<cmath> 21 #include<cstdlib> 22 #include<cstring> 23 #include<ctime> 24 #include<climits> 25 #define LL long long 26 #define maxn 1000005 27 #define M 1000000007 28 using namespace std; 29 int t, k; 30 char str[maxn]; 31 int hs[600]; 32 int ok[64]; 33 int nxt[64]; 34 int dp[maxn]; 35 int site[maxn]; 36 int sum[maxn]; 37 int main(){ 38 for(int i = ‘a‘ ;i <= ‘z‘ ;i ++) 39 { 40 hs[i] = i - ‘a‘; 41 } 42 for(int i = ‘A‘ ;i <= ‘Z‘; i++) 43 { 44 hs[i] = i - ‘A‘ + 26; 45 } 46 for(int i = ‘0‘ ;i <= ‘9‘; i ++) 47 { 48 hs[i] = i - ‘0‘ + 52; 49 } 50 scanf("%d",&t); 51 while(t--) 52 { 53 scanf("%d %s",&k,str); 54 int len = strlen(str); 55 memset(ok,0,sizeof(int)*k); 56 sum[0] = 0; 57 int wei = 0 ; 58 memset(nxt,-1,sizeof(int)*k); 59 int twei = 0 ; 60 int tt; 61 for(int i = len -1;i >= 0 ;--i) 62 { 63 site[i] = wei; 64 tt = nxt[hs[str[i]]] ; 65 if(wei){ 66 sum[wei] = (sum[wei]+sum[wei-1])%M; 67 dp[i] = sum[wei-1]; 68 if(site[tt] != wei) 69 { 70 sum[wei-1] = (sum[wei-1]-dp[tt]+M)%M; 71 }else{ 72 sum[wei] = (sum[wei]-dp[tt]+M)%M; 73 } 74 }else{ 75 sum[wei] += k-twei; 76 dp[i] = k -twei; 77 if(tt != -1) 78 { 79 sum[wei] -= dp[tt]; 80 } 81 } 82 if(ok[hs[str[i]]] == 0) 83 { 84 ok[hs[str[i]]] = 1; 85 twei ++ ; 86 } 87 if(twei == k ) 88 { 89 wei ++ ; 90 twei = sum[wei] = 0 ; 91 memset(ok,0,sizeof(int)*k); 92 } 93 nxt[hs[str[i]]] = i ; 94 } 95 if(!wei){ 96 printf("1 %d\n",k-twei); 97 }else{ 98 printf("%d %d\n",wei+1,sum[wei-1]); 99 } 100 } 101 return 0; 102 }
时间: 2024-12-29 23:23:05