您的位置:首页 > 其它

CodeForces 55D Beautiful numbers

2018-01-07 19:27 411 查看
         题意:求[l,r]内beautiful number的数量,如果一个数字能够整除它所有非零位那么它是beautiful number。

         首先推荐一个重要的结论sum%(n*x)%(x)==sum%x(n为正整数)。

       
其实感觉对于这个题来说,就是一个暴力。我们首先从暴力考虑,我们直接dfs状态肯定是(pos,now,lcm,isin),表示加数字到pos位了,现在加成的数字是什么,它的lcm是多少,是否在边界上。转移就是每次添加一个数字,每次添加一个数字。那么数位dp就是总结各个位置上的规律与共性,共性是什么呢,就要用上面的结论了。

        由于我们的边界是处理到最后(now%lcm==0)则答案是1,那么我们如果从now入手,我们值关心now取模之后的答案,所以借用上面的结论sum%(n*x)%(x)==sum%x,我们只需找到一个合适的(n*x)使得其对于所有模数都满足结论即可,那最小就是所有x即lcm的gcd,为2520了。

 
      所以我们就可将dp[i][j][k]定义为处理到第i位,lcm为j,now%2520为k的方案数了,可是这样会爆空间,考虑到j即lcm的数值并不是全部连续的,1-9的不同组合lcm就只有50种以内,所以多开一个数组rev[i]表示i这个lcm是第几大的进行离散化即可。

 
      下附AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 23
using namespace std;
typedef long long ll;
const int mod=2520;
ll l,r;
int cnt,tot;
int bit[maxn];
int rev[2550];
ll dp[maxn][50][2550];
ll gcd(ll x,ll y)
{
return y==0 ? x:gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
return x/gcd(x,y)*y;
}
ll dfs(ll pos,ll now,ll nowlcm,int isin)
{
if(!pos) return (now%nowlcm==0);
if(!isin && dp[pos][rev[nowlcm]][now]!=-1) return dp[pos][rev[nowlcm]][now];
int maxx=isin?bit[pos]:9;
ll ans=0;
for(int i=0;i<=maxx;i++)
{
ll nexlcm=(i==0?nowlcm:lcm(nowlcm,(ll)i));
ans+=dfs(pos-1,((now*10+i)%mod),nexlcm,isin&&i==maxx);
}
if(!isin) dp[pos][rev[nowlcm]][now]=ans;
return ans;
}
ll solve(ll now)
{
tot=0;
while(now)
{
bit[++tot]=now%10;
now/=10;
}
return dfs(tot,0,1,1);
}
int main()
{
for(int i=1;i<=mod;i++)
if(mod%i==0)
rev[i]=++cnt;
memset(dp,-1,sizeof(dp));
int _;
scanf("%d",&_);
while(_--)
{
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",solve(r)-solve(l-1));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: