题目链接:点击打开链接
题意:要求你生成一个合法的字符串, 由小写字母a~z组成, 相同字母相邻出现不能超过3个, 求有多少种组合。
思路:数位DP来做, 用d[i][j][k]表示处理完前i个字母, 第i-1个字母为j,已经连续出现了k次的方法数。 然后每次转移就很简单了, 继续选择字母j(if(k < 3)), 或者换其他的。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const ll mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; // & 0x7FFFFFFF const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 2000 + 10; int T,n,m,d[maxn][30][5],vis[maxn][30][5],kase=0; int dp(int i, int j, int k) { int& ans = d[i][j][k]; if(i == n+1) return 1; if(vis[i][j][k] == kase) return ans; vis[i][j][k] = kase; ans = 0; if(k < 3 && i != 1) { ans += dp(i+1, j, k+1); if(ans >= mod) ans -= mod; } for(int l=0;l<26;l++) { if(l == j) continue; ans += dp(i+1, l, 1); if(ans >= mod) ans -= mod; } return ans; } int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); ++kase; int ans = dp(1, 27, 0); printf("%d\n",ans); } return 0; }