BZOJ3134: [Baltic2013]numbers

138 篇文章 0 订阅

因为若一个数是回文数,那么他中间的2个数相等或3个数一定是回文数
典型数位DP,f[i][x][y][j][k]表示DP到第i位,前1位是j,这一位是k,有多少非回文数,x表示是否前面达到上限,y表示是否前导0

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define lowbit(x) x&(-x) 
using namespace std;

const int maxn = 32;
const int maxk = 12;
const int maxm = 910;
const ll Mod = 1e9+9;
//      up 0
ll f[2][2][2][11][11];
ll n,m;
int up[maxn],t[20],len;

ll solve(ll x)
{
    int now=0;
    memset(f[now],0,sizeof f[now]);

    len=0;
    while(x) t[++len]=x%10,x/=10;
    for(int i=1;i<=len;i++) up[i]=t[len-i+1];

    for(int i=0;i<=up[1];i++) f[now][i==up[1]][1][0][i]=1ll;
    for(int k=2;k<=len;k++)
    {
        now=1^now;
        memset(f[now],0,sizeof f[now]);
        for(int lu=0;lu<=1;lu++)
        {
            for(int lz=0;lz<=1;lz++)
            {
                int ui=lu?up[k-2]:9;
                for(int i=0;i<=ui;i++)
                {
                    int uj=lu?up[k-1]:9;
                    for(int j=0;j<=uj;j++)
                    {
                        int ux=lu?up[k]:9;
                        if(i==j)
                            if(i||!lz) continue;
                        for(int x=0;x<=ux;x++)
                        {
                            if(j==x)
                                if(j||(!lz|i)) continue;
                            if(i==x)
                                if(i||!lz) continue;
                            f[now][(x==up[k])&lu][lz&!i][j][x]+=
                                f[1^now][lu][lz][i][j];
                        }
                    }
                }
            }
        }
    }
    ll re=0;
    for(int u=0;u<=1;u++)
        for(int z=0;z<=1;z++)
            for(int i=0;i<=9;i++)
                for(int j=0;j<=9;j++) re+=f[now][u][z][i][j];
    return re;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    ll s1=n?solve(n-1):0ll;
    ll s2=solve(m);
    printf("%lld\n",s2-s1);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值