Let life be beautiful li|

Ginger_he

园龄:3年1个月粉丝:5关注:5

洛谷P6371题解

本文同步更新于洛谷博客

题目描述

使用给定的数字,组成一些在 [A,B] 之间的数使得这些数每个都能被 X 整除。

题解

对于 X>105,我们可以直接枚举 X 的倍数,然后判断其是否符合条件。
对于 X105,则使用数位 dp。我们传四个参数 k,s,t,u 进入 dfs,分别表示第 k 位,模 X 的余数为 s,这一位填的数有没有限制以及是否为前导 0,用 f 数组记忆化即可。

注意

要区分前导 0 和题目中给定的 0

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int len,a[15];
ll p,l,r,f[15][maxn];
bool vis[15];
char s[15];
ll dfs(int k,int s,int t,int u)
{
    if(!k)
        return s?0:1;
    if(!t&&!u&&f[k][s]!=-1)
	return f[k][s];
    int x=t?a[k]:9;
    ll res=0;
    if(u)
	res+=dfs(k-1,0,t&&!x,1);
    for(int i=0;i<=x;i++)
    {
	if(vis[i])
	{
	    if(u&&!i)
		continue;
	    res+=dfs(k-1,(s*10+i)%p,t&&(i==x),0);
	}
    }
    if(!t&&!u)
	f[k][s]=res;
    return res;
}
ll divide(ll x)
{
    len=0;
    while(x)
    {
	a[++len]=x%10;
	x/=10;
    }
    return dfs(len,0,1,1);
}
bool check(ll x)
{
    while(x)
    {
        if(!vis[x%10])
	    return 0;
	x/=10;
    }
    return 1;
}
int main()
{
    memset(f,-1,sizeof(f));
    scanf("%lld%lld%lld\n%s",&p,&l,&r,s+1);
    for(int i=1;s[i];i++)
        vis[s[i]-'0']=1;
    if(p<maxn)
	printf("%lld\n",divide(r)-divide(l-1));
    else
    {
	ll tmp=l%p?l/p+1:l/p,ans=0;
	for(ll i=tmp*p;i<=r;i+=p)
	    ans+=check(i);
	printf("%lld\n",ans);
    }
    return 0;
}

本文作者:Ginger_he

本文链接:https://www.cnblogs.com/Gingerhe/p/16056907.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Ginger_he  阅读(41)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起