数位dp

考虑记搜实现,在过程中维护:

cur:目前到第几位

lim:是否卡着上界

sta:是否有前导零

...:你其他要维护的

windy数:https://www.luogu.org/problem/P2657

板题

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef double db;
#define pii pair<int,int>
#define mp make_pair
#define llinf 9000000000000000000LL
#define B cout << "breakpoint" << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1; 
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
int num[20];
int f[20][20][2][2];
int dfs(int cur,bool start,bool lim,int pre)
{
    if(f[cur][pre][start][lim] != -1) return f[cur][pre][start][lim];
    if(cur == 0) return 1; 
    int ans = 0;
    int res = lim ? num[cur] : 9;
    for(int i = 0;i <= res;i++)
    {
        if(start)
        {
            if(abs(pre - i) < 2) continue;
            ans += dfs(cur - 1,start,(i == res && lim),i);
        }
        else
        {
            if(i == 0) ans += dfs(cur - 1,start,(lim && i == res),i);
            else ans += dfs(cur - 1,1,(lim && i == res),i);
        }
    }
    return f[cur][pre][start][lim] = ans;
}
int ans;
int solve(int x)
{
    int k = 0;
    while(x)
    {
        num[++k] = x % 10;
        x /= 10;
    }
    memset(f,-1,sizeof(f));
    return dfs(k,0,1,-10);
}
int main()
{
    int a = read(),b = read();
    if(a == 1) printf("%d",solve(b) - solve(a - 1) - 1);
    else printf("%d",solve(b) - solve(a - 1));
}
View Code

AHOI2009 同类分布:https://www.luogu.org/problem/P4127

考虑维护f[i][j][k]:到第i位,前面数字和是j,模完的答案是k

枚举模数即可

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef double db;
typedef int mainint;
#define pii pair<int,int>
#define int long long
#define O(x) cout << #x << " " << x << endl;
#define mp make_pair
#define llinf 9000000000000000000LL
#define B cout << "breakpoint" << endl;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1; 
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
const int N = 22;
const int maxn = 205;
int f[N][maxn][maxn][2],num[N],M;
int dfs(int cur,int sum,int mod,bool lim)
{
    if(cur == 0) return f[cur][sum][mod][lim] = (mod == 0 && sum == M);
    if(f[cur][sum][mod][lim] != -1) return f[cur][sum][mod][lim];
    int res = lim ? num[cur] : 9;
    int ans = 0;
    for(int i = 0;i <= res;i++)
        ans += dfs(cur - 1,sum + i,(mod * 10 + i) % M,(lim && i == res));
    return f[cur][sum][mod][lim] = ans;
}
int solve(int x)
{
    int k = 0,tot = 0;
    while(x)
    {
        num[++k] = x % 10;
        tot += x % 10;
        x /= 10;
    }
    int ans = 0;
    for(M = 1;M <= k * 9;M++)
    {
        memset(f,-1,sizeof(f));
        ans += dfs(k,0,0,1);
    }
    return ans;
}
mainint main()
{
    int a = read(),b = read();
    printf("%lld
",solve(b) - solve(a - 1));
}
View Code

萌数:https://www.luogu.org/problem/P3413

我们只要处理回文子串长度为2或3,即可包含所有情况

那么维护last和lalast,上一位和上两位,维护去掉前导零之后目前是第几位即可

注意,n较大时要字符串读入

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef int mainint;
#define int long long
const ll mod = 1000000007;
#define O(x) cout << #x << " "  << x << endl;
#define B cout << "breakpoint" << endl;
int dp[1005][10][10][3][2][2],a[1005];
int L,R,len;
int dfs(int cur,int la,int lala,int sta,int lim,int have)
{
    if(cur == 0) return have;
    if(dp[cur][la][lala][sta][lim][have]!=-1) return dp[cur][la][lala][sta][lim][have];
    int ret=0;
    int res=lim?a[cur]:9;
    //printf("%lld %lld %lld %lld %lld %lld
",la,res,sta,lim,cur,have);
    for(int i=0; i<=res; i++)
    {
        if(sta==2)
        {
            if(!i)  (ret+=dfs(cur-1,i,la,2,0,have))%=mod;
            else (ret+=dfs(cur-1,i,la,1,lim && i == res,have))%=mod;
        }
        else if( (i==lala && !sta) || i == la) (ret+=dfs(cur-1,i,la,0,lim&&i==res,1))%=mod;
        else (ret+=dfs(cur-1,i,la,0,lim&&i==res,have))%=mod; 
    }
    dp[cur][la][lala][sta][lim][have]=ret;
    return ret;
}
char s[2005];
mainint main()
{
    scanf("%s",s + 1);
    len = strlen(s + 1);
    memset(dp,-1,sizeof(dp));
    for(int i = 1;i <= len;i++) a[i] = s[len - i + 1] - '0';
    int i = 1;
    while(1)
    {
        if(a[i] > 0) {a[i]--; break; }
        else a[i] += 9,i++;
    }
    ll ans1 = dfs(len,0,0,2,1,0);
    
    scanf("%s",s + 1);
    len = strlen(s + 1);
    memset(dp,-1,sizeof(dp));
    for(int i = 1;i <= len;i++) a[i] = s[len - i + 1] - '0';
    ll ans2 = dfs(len,0,0,2,1,0);
    
    printf("%lld
",((ans2 - ans1) % mod + mod) % mod);
    return 0;
}
View Code

储能表https://www.luogu.org/problem/P4067

原文地址:https://www.cnblogs.com/LM-LBG/p/11253187.html