【算法】数位DP

【题解】动态规划

题目要求的是大整数……没办法只写了小数字的,感觉应该没错。

大题框架是最大值最小化的二分问题。

对于每一块要求count(b)-count(a-1)≥s

已知a如何计算b?令now=count(a-1)+s,求的就是满足count(b)≥now的最小b了。

虽然看上去只是不等式的移项,但其实上是一种差分思想:将b-a≥s转化为b≥a+s,避免计算b和a的差。

然后每次求出b后,b+1就是新的起点,也就是count(b)=count(a`-1),不需要重新计算。

那么如何计算count(i)?画画图就大概知道了:

预处理f[i]表示以高度i为根(不考虑自身)的1的数量,f[i]=f[i-1]*2+(1<<(i-1))。

每次从根到叶子判断若加上左子树权值(左子树包含的数字中所有1的数量)仍≤now就走右子树。

权值如何计算?ans=ans+f[j]+tot*(1<<j)+1,f[j]是假设上面的位是0考虑的,tot表示上面1的数量。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[],k,M;
bool calc(int s)
{
int n=,now=,i,cpnow=,tot=;
for(i=;i<=M;i++)
{
now=;tot=;n=;
for(int j=k-;j>=;j--)
{
if(now+f[j]+tot*(<<j)+<=cpnow+s)
{
now=now+f[j]+tot*(<<j)+;
n|=(<<j);
tot++;
}
}
printf("s=%d n=%d now=%d\n",s,n,now);
if(n==(<<k)-)return ;
cpnow=now;
}
return ;
}
int main()
{
scanf("%d%d",&k,&M);
f[]=;
for(int i=;i<=;i++)
{
f[i]=f[i-]*+(<<(i-));
}
int l=,r=(<<k)-;
while(l<r)
{
int mid=(l+r)>>;
if(calc(mid))r=mid;
else l=mid+;
}
printf("%d",l);
return ;
}

最新文章

  1. CYQ.Data V5 从入门到放弃ORM系列:教程 - MAction类使用
  2. Mongoose使用案例--让JSON数据直接入库MongoDB
  3. linux系统无法启动解决方案
  4. C#算法之向一个集合中插入随机不重复的100个数
  5. C#设计模式——适配器模式(Adapter Pattern)
  6. JSP文件编码
  7. winform异步进度条LongTime
  8. 每天一条linux命令——login
  9. SZU:A66 Plastic Digits
  10. vuejs使用jsx语法
  11. vue 定义全局函数,监听android返回键事件
  12. APPLE-SA-2019-3-25-2 macOS Mojave 10.14.4,Security Update 2019-002 High Sierra, Security Update 2019-002 Sierra
  13. GetLastError获取到错误代码的含义
  14. C#读取CSV
  15. vue项目webpack打包后有的文件big 问题
  16. web网页上面调用qq
  17. MySQL 查看执行的SQL记录
  18. iOS 源代码混淆(初步混淆)
  19. HashMap+双向链表手写LRU缓存算法/页面置换算法
  20. 使用admin lte 碰到访问Google字体的问题

热门文章

  1. android BadgeView的使用(图片上的文字提醒)
  2. lintcode-151-买卖股票的最佳时机 III
  3. LintCode-373.奇偶分割数组
  4. Java-编译后出现$1.class、$2.class等多个class文件
  5. c语言作业1
  6. try catch finally 与continue的使用
  7. JSTL标签之核心标签
  8. JavaScript Array 类型
  9. hdu 1690 Bus System (最短路径)
  10. 2017中国大学生程序设计竞赛-哈尔滨站 H - A Simple Stone Game