数位dp

不要62和带4的值 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;

int data[20];
ll dp[25][2];

ll dfs(int pos, int h, int sta, bool limit)  //limit为临界判断,pos为当前位数(从高到低)其他值根据题意设置
{
    if(pos == 0) return 1;

    if(!limit && dp[pos][sta]!=-1) return dp[pos][sta];  //一般不变

    int up = limit ? data[pos] : 9;  //当前位最大值
    ll ans = 0;

    for(int i = 0; i <= up; i++)
    {
        if(i==4) continue;  //不满足的条件
        if(h==6&&i==2) continue;
        ans += dfs(pos - 1, i, i==6, i == data[pos] && limit);  //递归
    }

    if(!limit) dp[pos][sta] = ans;  //记忆化
    return ans;
}
//将每一位存起来
ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[++pos] = n % 10;
        n /= 10;
    }
    return dfs(pos , 0, 1, true);
}

int main()
{
    ll a, b;
    int cnt = 0;
    memset(dp, -1, sizeof(dp));
    while(~scanf("%lld %lld", &a, &b)&&(a||b))
    {
        printf("%lld\n", solve(b) - solve(a - 1));
    }
    return 0;
}

只要带49的数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;

int data[20];
ll dp[25][2][2];

ll dfs(int pos, int h, int sta, bool limit)
{
    if(pos == 0)
        return h;

    if(!limit && dp[pos][h][sta]!=-1)
        return dp[pos][h][sta];

    int up = limit ? data[pos] : 9;
    ll ans = 0;

    for(int i = 0; i <= up; i++)
    {
        if(sta&&i==9) 
            ans += dfs(pos-1,1,0,i==data[pos]&&limit);   //符合条件
        else
            ans+=dfs(pos-1,h,i==4,i==data[pos]&&limit);  //不符合条件
    }

    if(!limit)
        dp[pos][h][sta] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[++pos] = n % 10;
        n /= 10;
    }
    return dfs(pos, 0, 0, true);
}

int main()
{
    ll a, n;
    scanf("%lld",&n);
    int cnt = 0;
    memset(dp, -1, sizeof(dp));
    while(n--)
    {
        scanf("%lld", &a);
        printf("%lld\n", solve(a));
    }
    return 0;
}

能被13整除并带13的数字

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;

int data[20];
ll dp[25][2][20][10];

ll dfs(int pos, int h,int k, int sta, bool limit)  k为当前数取余13的值,又a%mod+b%mod=(a+b)%mod可以验证方法正确
{
    if(pos == 0)
        return h==1&&k==0;
    if(!limit && dp[pos][h][k][sta]!=-1)
        return dp[pos][h][k][sta];
    int up = limit ? data[pos] : 9;
    ll ans = 0;
    for(int i = 0; i <= up; i++)
    {
        if(sta==1&&i==3)
            ans+= dfs(pos-1,1,(k*10+i)%13,i,i==data[pos]&&limit);  //判断是否含13
        else
            ans+=dfs(pos-1,h,(k*10+i)%13,i,i==data[pos]&&limit);
    }
    if(!limit)
        dp[pos][h][k][sta] = ans;
    return ans;
}

ll solve(ll n)
{
    int pos = 0;
    while(n)
    {
        data[++pos] = n % 10;
        n /= 10;
    }
    return dfs(pos, 0, 0,0, true);
}

int main()
{
    ll a;
    memset(dp, -1, sizeof(dp));
    while(~scanf("%lld", &a))
        printf("%lld\n", solve(a));
    return 0;
}

HDU - 3709   找到平衡支点, 例如4139中以3为支点4*2 + 1*1 = 9 and 9*1 = 9,则该数为我们要找的数。

这题多出来的一步是找平衡支点,遍历查找即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long ll;

int data[20];
ll dp[25][25][2100];
ll maxx;
ll dfs(int pos, int o,int  sta, bool limit)
{
    if(pos == 0)
        return sta==0;
    if(sta<0)
        return 0;
    if(!limit && dp[pos][o][sta]!=-1)
        return dp[pos][o][sta];
    int up = limit ? data[pos] : 9;
    ll ans = 0;
    for(int i = 0; i <= up; i++)
        ans+=dfs(pos-1,o,sta+i*(pos-o),i==data[pos]&&limit);
    if(!limit)
        dp[pos][o][sta] = ans;
    return ans;
}
ll solve(ll n)
{
    int pos = 0;
    ll ans=0;
    while(n)
    {
        data[++pos] = n % 10;
        n /= 10;
    }
    for(int i=1; i<=pos; i++)
        ans+=dfs(pos,i,0, 1);
    return ans+1-pos;  //0000计算了4次,减去pos-1次
}

int main()
{
    ll a,n,b;
    memset(dp, -1, sizeof(dp));
    scanf("%lld",&n);
    while(n--)
    {
        scanf("%lld %lld", &a,&b);
        printf("%lld\n",solve(b)-solve(a-1));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值