5379. 【NOIP2017提高A组模拟9.21】Victor爱数字 (2017.9B组)

Description

Victor 是一名热爱数字的同学。他最近在思考这样一个问题:
一个字符串是回文的当且仅当它倒过来还和原来相同。那么如果一个数的数串没有一个长度超过1 的子串是回文串的话,它就是palindrome-free 的。例如:16276 是palindrome-free的,而17276 不是,因为它包含了回文串727。
Victor 想知道在a 到b 的区间内,有多少个数是palindrome-free 的。

Input

从文件numbers.in 中读入数据。
包括两个数字a,b。

Output

输出到文件numbers.out 中。
输出包含一个整数:区间a,…,b 中palindrome-free 的数的总个数(包括a,b)。

Sample Input

输入1:
123 321

输入2:
123456789 987654321

Sample Output

输出1:
153

输出2:
167386971

Data Constraint

对于16% 的数据,b - a <= 200。
对于24% 的数据,b - a <= 10^5。
对于32% 的数据,b - a <= 10^6。
对于100% 的数据,0 <= a <= b <= 10^18
想法:
数论,ans=ans(b)-ans(a-1);
如果一个数是palindrome-free的,则必有s[i]==s[i+1]||s[i]==s[i+2]
32%
如何求ans(x)?
设f[i][j][k][0/1][0/1][0/1]为构造到第i位,第i-1位为j,第i位为k,第i-1位为是否为前导0,第i位是否为前导0,前i位是否与x的前i位一样
递归求会更好
code

#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
ll f[21][11][11][2][2][2],a[19],b[19],n,m;
ll gets(ll x,ll i1,ll j3,ll i2,ll j2,ll full)
{
    if (f[x][i1][j3][i2][j2][full]>0) return f[x][i1][j3][i2][j2][full];
    ll bj,bz1,bz2;
    if (x==a[0])
    {
        f[x][i1][j3][i2][j2][full]=1;
        return f[x][i1][j3][i2][j2][full];
    }
    ll i,sum=0;
    if ((full==1)||(x==0)) bj=a[x+1];else bj=9; 
    for (i=0;i<=bj;i++)
    {
        if (((i!=j3)||(j2==0))&&((i!=i1)||(i2==0)))
        {
            if (((full==1)||(x==0))&&(i==a[x+1])) bz1=1;else bz1=0;
            if ((j2==0)&&(i==0)) bz2=0;else bz2=1;
            sum+=gets(x+1,j3,i,j2,bz2,bz1); 
        }   
    }
    f[x][i1][j3][i2][j2][full]=sum;
    return sum;
}
ll get(ll n)
{
    memset(f,0,sizeof(f));
    if (n<0) return 0;
    if (n<10) return n+1;
    a[0]=0;
    ll t;
    while (n>0)
    {
        a[++a[0]]=n%10;
        n/=10;
    }
    ll i;
    for (i=1;i<=a[0]/2;i++)
    {
        t=a[i];
        a[i]=a[a[0]-i+1];
        a[a[0]-i+1]=t;  
    }
    return gets(0,0,0,0,0,0);
}
int main()
{
    freopen("numbers.in","r",stdin);
    freopen("numbers.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    ll ans=get(m);
    ans-=get(n-1);
    printf("%lld",ans); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值