HDU 5642 King's Order(数位DP)

时间:2022-12-16 09:08:18

题目链接:点击打开链接

题意:要求你生成一个合法的字符串, 由小写字母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;
}