首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Codeforces Beta Round #51 D. Beautiful numbers(数位dp+思维)

Codeforces Beta Round #51 D. Beautiful numbers(数位dp+思维)

作者头像
Ch_Zaqdt
发布2019-01-28 10:21:33
3240
发布2019-01-28 10:21:33
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACMZaqdt_ACM

题目链接:http://codeforces.com/contest/55/problem/D

       题意就是给你一个范围,问这个范围内有多少个数是它各位非零数的倍数。

       思路就是数位dp,但是要求这个数要能整除各个非零位,这个状态不太好标记,所以这里就需要用一点数学知识了,一个数可以整出这个数的每一位非零数,那么只要可以整出每一位非零数的lcm就好了,然后我们可以算出1-9的lcm是2520,所以我们只需要去标记每个数的每一位数的lcm的状态就好了。这样的空间复杂度就缩小到了20*2520*2520,但是这样还是很大,然后我们发现1-9的lcm的个数并不多,所以这里又可以用离散化优化到20*30*2520,然后跑一遍就可以了。


AC代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[20];
ll dp[20][50][2550];
int Hash[2550];

void init(){
  int cnt = 0;
  memset(dp, -1, sizeof(dp));
  for(int i=1;i<=2520;i++){
    if(2520 % i == 0) Hash[i] = cnt++;
  }
}

ll lcm(ll x, ll y){
  return x / __gcd(x, y) * y;
}

ll dfs(int pos, int prelcm, int prenum, bool limit){
  if(pos == -1) return prenum % prelcm == 0;
  if(!limit && dp[pos][Hash[prelcm]][prenum] != -1)
    return dp[pos][Hash[prelcm]][prenum];
  int up = limit ? a[pos] : 9;
  ll ans = 0;
  for(int i=0;i<=up;i++){
    int nownum = (prenum * 10 + i) % 2520;
    int nowlcm = prelcm;
    if(i) nowlcm = lcm(prelcm, i);
    ans += dfs(pos - 1, nowlcm, nownum, limit && i == up);
  }
  if(!limit) dp[pos][Hash[prelcm]][prenum] = ans;
  return ans;
}

ll solve(ll x){
  int pos = 0;
  while(x){
    a[pos++] = x % 10;
    x /= 10;
  }
  return dfs(pos - 1, 1, 0, true);
}

int main()
{
  int T;
  scanf("%d",&T);
  init();
  while(T--){
    ll l, r;
    scanf("%lld%lld",&l, &r);
    printf("%lld\n", solve(r) - solve(l - 1));
  }
  return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年01月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档