题面

传送门:UOJ


Solution

这题的数位DP好蛋疼啊qwq

好吧,我们说回正题。

首先,我们先回忆一下LUCAS定理:

\(C_n^m \equiv C_{n/p}^{m/p} \times C_{n\%p}^{m\%p} (\%p)\)

我们仔细观察这个定理,就可以发现一个事实:LUCAS定理本质上是在对n,m两个数做K进制下的数位分离

所以说,LUCAS定理我们可以这样表示:

\(C_n^m \equiv \prod C_{a_i}^{b_i}\)

(ai与bi为K进制拆分后的两个数的每一位数,若一个数的位数不足另一个数,则以前导零填充

我们要判断一个\(C_n^m\)是否能被K整除,只需要保证其中一个\(C_{a_i}^{b_i}\)能被K整除(即同余K为零)就好。

又因为K为质数,且ai,bi均小于K,所以说我们要使得\(C_{a_i}^{b_i}\)为0,必须有\(b_i\)>\(a_i\)

.

.

所以说,问题就变为了对于有多少个\((i,j)\)使得\(j\)中某一位\(>i\)

这个新的问题显然可以用数位DP来解决。

在这里,我使用记忆化搜索来写(用记忆化可以减少讨论数)

考虑这样设状态:

设\(f[x][0/1][0/1][0/1][0/1][0/1]\)表示填到第\(x\)位,

i是否卡上界n,j是否卡上界m,j是否卡上界 \((j<i)\),上一位是否为前导零(这道题不需要,但是为了模板完整性。我还是写上去了),之前是否有某一位达成需求,之后可以达成的总共的可行方案数

转移非常好讨论,我们只需要注意一下j的上界是两个限制的最小值就好。

我是这样写转移的:

for(int i=0;i<=(limit1==true?l1[to]:K);i++)
{
int t_j=(limit2==true?l2[to]:K);
t_j=(limit3==true?min(i,t_j):t_j);
for(int j=0;j<=t_j;j++)
{
t_ans+=dfs(to+1,limit1==true and i==l1[to],limit2==true and j==l2[to],limit3==true and j==i,zero==true and i==0,OK==true or j>i);
t_ans%=poi;
}
}

这样子写,看起来时间复杂度是

\(O(T*n^2*2^5)\)

但是因为我们会少讨论很多没有意义的情况,所以说能跑得过去。

确切复杂度我不会算qwq

还请dalao们指点


Code

//BZOJ 4737: 组合数问题
//Jan,14th,2019
//LUCAS定理的运用+鬼畜数位DP
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int poi=1000000007;
const int N=70;
long long f[N][2][2][2][2][2];//到i位,底数卡不卡n,指数卡不卡m,指数卡不卡底数,zero,OK
int n,l1[N],l2[N],K;
long long dfs(int to,bool limit1,bool limit2,bool limit3,bool zero,bool OK)
{
if(f[to][limit1][limit2][limit3][zero][OK]>=0) return f[to][limit1][limit2][limit3][zero][OK];
long long t_ans=0;
if(to==n+1)
{
if(OK==true)
t_ans=1;
return f[to][limit1][limit2][limit3][zero][OK]=t_ans;
}
for(int i=0;i<=(limit1==true?l1[to]:K);i++)
{
int t_j=(limit2==true?l2[to]:K);
t_j=(limit3==true?min(i,t_j):t_j);
for(int j=0;j<=t_j;j++)
{
t_ans+=dfs(to+1,limit1==true and i==l1[to],limit2==true and j==l2[to],limit3==true and j==i,zero==true and i==0,OK==true or j>i);
t_ans%=poi;
}
}
return f[to][limit1][limit2][limit3][zero][OK]=t_ans;
}
int main()
{
int T=read();K=read();
for(;T>0;T--)
{
n=0;
long long num1=read(),num2=read();
num2=min(num1,num2);//防止m>n while(num1!=0)
l1[++n]=num1%K,num1/=K;
for(int i=1;i<=n;i++)
l2[i]=num2%K,num2/=K;
reverse(l1+1,l1+1+n);
reverse(l2+1,l2+1+n);
memset(f,0x80,sizeof f);
K--;
dfs(1,true,true,true,true,false);
K++; printf("%lld\n",f[1][true][true][true][true][false]);
}
return 0;
}

[UOJ 275/BZOJ4737] 【清华集训2016】组合数问题 (LUCAS定理的运用+数位DP)的更多相关文章

  1. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

  2. UOJ#275. 【清华集训2016】组合数问题 数位dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ275.html 题解 用卢卡斯定理转化成一个 k 进制意义下的数位 dp 即可. 算答案的时候补集转化一下 ...

  3. uoj#275. 【清华集训2016】组合数问题(数位dp)

    传送门 假设有\(k|{n\choose m}\),因为\(n!\)中质因子\(k\)的次数为\(S(n)=\left\lfloor\frac{n}{k}\right\rfloor+\left\lfl ...

  4. UOJ #269. 【清华集训2016】如何优雅地求和

    UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...

  5. [UOJ#276]【清华集训2016】汽水

    [UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...

  6. UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]

    #274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...

  7. UOJ275 [清华集训2016] 组合数问题 【Lucas定理】【数位DP】

    题目分析: 我记得很久以前有人跟我说NOIP2016的题目出了加强版在清华集训中,但这似乎是一道无关的题目? 由于$k$为素数,那么$lucas$定理就可以搬上台面了. 注意到$\binom{i}{j ...

  8. UOJ #276「清华集训2016」汽水

    为什么你们常数都这么小啊 UOJ #276 题意:在树上找一条链使得|边权平均值$ -k$|尽量小,$ n<=5e4$ $ Solution:$ 首先二分答案$ ans$,即我们需要找一条链使得 ...

  9. uoj#274. 【清华集训2016】温暖会指引我们前行

    http://uoj.ac/problem/274 由于边权互不相同,只需用lct维护带加边的最大生成树 #include<bits/stdc++.h> #define lc ch][0 ...

随机推荐

  1. nginx 1.12安装

    准备工作 使用root用户安装. 到nginx官网下载Linux源码或者执行:wget http://nginx.org/download/nginx-1.12.2.tar.gz. 到pcre站点下载 ...

  2. 「面试」拿到B站的意向书

    此次B站服务端开发面试之旅可谓惊险,不过通过对大部分面试题套路的掌握,不出意外还是拿下了,下面我们来看看这些骚题是不是常见的不能再常见的了.这些面试题看了就能面上?当然不是,只是通过这些题让自己知道所 ...

  3. A4988两相四线步进电机驱动模块使用经验

    1.A4988模块可以驱动两相四线步进电机,模块引脚及接线图如下: 2.步进电机引线如下: 3.引脚: ENABLE:低电平有效,用于打开和关闭场效应管的输出: RESET:低电平有效,芯片复位: S ...

  4. Gearman实战第一弹:异步处理结算单

    昨天梦回jm,醒来之后看着窗外万里晴空,想大声喊一句:爷青回! 我想起之前使用gearman的岁月.不知不觉也过了快5年,想总结一篇关于gearman的技术文章算是一种对青春的祭奠,再不写的话更少有p ...

  5. 【手摸手,带你搭建前后端分离商城系统】01 搭建基本代码框架、生成一个基本API

    [手摸手,带你搭建前后端分离商城系统]01 搭建基本代码框架.生成一个基本API 通过本教程的学习,将带你从零搭建一个商城系统. 当然,这个商城涵盖了很多流行的知识点和技术核心 我可以学习到什么? S ...

  6. 多测师讲解自动化--rf关键字--断言(下)_高级讲师肖sir

    断言: 1.1Page Should Contain Maximize Browser Window sleep 2 Comment Page Should Contain hao123 #断言当前页 ...

  7. 多测师讲解selenium__论坛验证码_处理方法_ 高级讲师肖sir

    1.登录我们搭建的论坛环境 2. 3. 4.

  8. IDEA SpringBoot+JPA+MySql+Redis+RabbitMQ 秒杀系统

    先放上github地址:spike-system,可以直接下载完整项目运行测试 SpringBoot+JPA+MySql+Redis+RabbitMQ 秒杀系统 技术栈:SpringBoot, MyS ...

  9. 【C/C++编程入门学习】同样是数据类型,链表对比数组?哪一个更香?

    说起链表,第一反应:链表是一种数据类型!它可以用来存储同种类型多个批量数据.   有了这种认知,很容易去联想到数组,它也是一种数据类型,也可以用来存储同种类型的批量数据.初学者往往对数组的印象比较好, ...

  10. 程序员的“三十而已”,你都30岁了,不会还在XXX吧?

    一部<三十而已>火了 太太们的包包鄙视链出圈了 有人的地方就有江湖 是的,程序员入圈是容易的 不需要4万的LV,更不需要限量版的爱马仕 只需要一件耐躁的格子衫 然而,程序员的30岁, 却说 ...