[Luogu P1066] 2^k进制数 (组合数或DP)
题面
传送门:https://www.luogu.org/problemnew/show/P1066



Solution
这是一道神奇的题目,我们有两种方法来处理这个问题,一种是DP,一种是组合数。
这题需要高精度,以下省略此声明
.
如果你对数学不感兴趣/喜欢写DP/(不想虐待自己),这里是DP做法。
首先,我们可以发现,这个数最多有w/k位(向上取整),如下图所示:

那么,我们就可以以这个特性做DP啦。
设f[i][j]表示枚举到第i位(指2^k进制下的),最后一位数为j。
f[i][j] = ∑ f[i-1][k] ((j==0 and k==0) or k<j)
这里的k显然是可以用前缀和优化的
初始化 f[1][i]=1 (i=0~2^(w%k)-1)
当然,还有一些小细节:f[倒数第2/第1个][0]=0
答案为∑f[w/k][i]
(因为我没写过DP做法,这个做法纯口胡,如有错误请通知蒟蒻博主)
那....组合数呢?
事实上,这题的组合数做法的确很妙,(当然也有不少细节)
假设我们枚举了第一位数,那么后面位数的方案数是可以通过组合数来计算出来的。
因为后面的数要比第一位大,那么后面的数相当于从 [第一位数+1,2^k-1] 这个数的区间中选出x个数(x为后面的位数数量)来 (因为每一种方案都可以通过摆成升序满足题目要求)。
但是考虑到有可能有若干个前导零,我们还要枚举第一个位数从哪开始。
因为枚举了前导零,我们枚举第一位数时应该从1开始(从0开始会有重复)
这样子,答案为:

(事实上口胡起来简单,写起来还有很多细节,这得亲自体会然后就会感到这题的毒瘤)
就酱,我们就可以切掉嘴巴AC出这道题啦(~ ̄▽ ̄)~
Code
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Int128
{
static const int N=500;
int a[N],len;
Int128()
{
memset(a,0,sizeof a);
len=0;
}
void Print()
{
for(int i=len;i>=1;i--)
printf("%d",a[i]);
}
friend Int128 operator * (Int128 A,int B)
{
for(int i=1;i<=A.len;i++)
A.a[i]*=B;
bool IsFullZero=true;
for(int i=1;i<=A.len;i++)
{
if(A.a[i]>=10)
{
A.a[i+1]+=A.a[i]/10,A.a[i]%=10;
if(i==A.len and A.a[i+1]!=0)
A.len++;
}
if(A.a[i]!=0) IsFullZero=false;
}
if(IsFullZero==true) A.len=1;
return A;
}
friend Int128 operator / (Int128 A,int B)
{
Int128 ans;
int temp=0;
for(int i=A.len;i>=1;i--)
{
temp=temp*10+A.a[i];
if(temp>=B)
{
ans.a[i]=temp/B,temp=temp%B;
ans.len=max(ans.len,i);
}
}
return ans;
}
friend Int128 operator + (Int128 A,Int128 B)
{
if(A.len<B.len) swap(A,B);
for(int i=1;i<=A.len;i++)
{
A.a[i]=A.a[i]+B.a[i];
if(A.a[i]>9)
{
A.a[i+1]++;A.a[i]-=10;
if(i==A.len)
A.len++;
}
}
return A;
}
};
const int N=1<<(9+1);
Int128 C[N];
int n,x,K,w,first,m;
int main()
{
scanf("%d%d",&K,&w); first=1<<(w%K),x=w/K;
if(w%K==0)
first=1<<K,x--;
m=1<<K; Int128 ans;
for(int j=0;j<=x-1;j++)
{
int tx=x-j;
memset(C[tx].a,0,sizeof C[tx].a);
C[tx].a[1]=1,C[tx].len=1;
for(int i=tx+1;i<=m;i++)
{
memset(C[i].a,0,sizeof C[i].a);
C[i]=(C[i-1]*i)/(i-tx);
}
if(j!=0) first=m;
for(int i=1;i<m and i<first;i++)
{
if(m-1-i<tx) break;
ans=ans+C[m-1-i];
}
//ans.Print();
//cerr<<endl;
} ans.Print();
return 0;
}
[Luogu P1066] 2^k进制数 (组合数或DP)的更多相关文章
- [luogu]P1066 2^k进制数[数学][递推][高精度]
[luogu]P1066 2^k进制数 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻 ...
- Luogu P1066 2^k进制数 组合数学
分两种情况:$k|n$和$k$不整除$n$ 如果$k|n$,那么长度为$n$的二进制数就能被恰好分成$n/k$个块:所以若某个数长度是$x$个块,由于每个块内能填不同的$2^k-1$个数,那么就有$C ...
- 洛谷P1066 2^k进制数
P1066 2^k进制数 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. ( ...
- 洛谷 P1066 2^k进制数
P1066 2^k进制数 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. ( ...
- 洛谷P1066 2^k进制数(题解)(递推版)
https://www.luogu.org/problemnew/show/P1066(题目传送) (题解)https://www.luogu.org/problemnew/solution/P106 ...
- [NOIP2006] 提高组 洛谷P1066 2^k进制数
题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后 ...
- P1066 2^k进制数
传送门 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进 ...
- 【洛谷p1066】2^k进制数
(不会敲键盘惹qwq) 2^k进制数[传送门] 算法标签: (又是一个提高+省选-的题) 如果我说我没听懂你信吗 代码qwq: #include<iostream> #include< ...
- 一本通1649【例 2】2^k 进制数
1649:[例 2]2^k 进制数 时间限制: 1000 ms 内存限制: 524288 KB [题目描述] 原题来自:NOIP 2006 提高组 设 r 是个 2k 进制数,并满足以 ...
随机推荐
- Python-__init__ 和 __new__区别和原理
__init__ 和 __new__区别 1. 从传递参数角度看,__init__第一个参数是实例本身, __new__传递的是类本身 2. 从执行顺序角度看,__new__方法执行在 __init_ ...
- 使用模拟退火算法优化 Hash 函数
背景 现有个处理股票行情消息的系统,其架构如下: 由于数据量巨大,系统中启动了 15 个线程来消费行情消息.消息分配的策略较为简单:对 symbol 的 hashCode 取模,将消息分配给其中一个线 ...
- 01 百度 AI Studio 基础操作记录(一) Notebook
转载参考: AI Studio基本操作(一) Notebook篇 一.基础 1.新建文件: 可以使用命令, !cat <<newfile > newfile.py 在项目空间内直接创 ...
- P4454 [CQOI2018]破解D-H协议
链接 这题并不难只是需要把题读懂 - By ShadderLeave 一句话题意 给定两个数 \(p\)和\(g\),有\(t\)组询问,每组询问给出\(A\)和\(B\) 其中 A = \(g^a ...
- Trie树【字典树】浅谈
最近随洛谷日报看了一下Trie树,来写一篇学习笔记. Trie树:支持字符串前缀查询等(目前我就学了这些qwq) 一般题型就是给定一个模式串,几个文本串,询问能够匹配前缀的文本串数量. 首先,来定义下 ...
- Vue结合Django-Rest-Frameword结合实现登录认证(二)
作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/2436173500265335 微信公众 ...
- 获取Jetbrain全家桶激活码
支持正版,本KEY仅用于体验软件 激活码 激活码一: 2GCA2ZHNKP-eyJsaWNlbnNlSWQiOiIyR0NBMlpITktQIiwibGljZW5zZWVOYW1lIjoi5r+A5r ...
- shell-的特殊变量-进程状态变量$$ $! $? $_详解
一:shell的特殊变量-进程状态变量详解 1. 进程状态变量 $$ 获取当前shell的进程号(pid) $! 执行上一个指令的pid,上一个后台运行进程的进程号 $? 获取执行上一个指令的返回值 ...
- ansible-playbook流程控制-when条件判断
1. ansible-playbook添加判断 when相当于shell脚本里的if 判断,when语句就是用来实现这个功能的,它是一个jinja2的语法,但是不需要双大括号,用法很简单 1 ...
- java安全编码指南之:锁的双重检测
目录 简介 单例模式的延迟加载 double check模式 静态域的实现 ThreadLocal版本 简介 双重检测锁定模式是一种设计模式,我们通过首次检测锁定条件而不是实际获得锁从而减少获取锁的开 ...