Online Judge:从Topcoder搬过来,具体哪一题不清楚

Label:状压Dp+前缀和优化

题目描述

给定两个数A和N,形成一个长度为N+1的序列,(A,A+1,A+2,...,A+N-1,A+N)。

每次操作可以把第i个数上的第x位数字删除,形成一个新的数字。

每个数字可以操作任意次,但不可以全部删完。

求有多少种方案,使得最后的序列中数字是单调不递减的。

两种方案是认为不同,如果第i个数的第x位在一个方案中被删除,在另一个方案中,没有被删除。

Tip:注意一个数字不能所有位全部删光,至少得有一位还保存着。另外,假如数字\(100\)删成\(00\)或\(0\),他们表示的值都是0,但两种方案视为不同。

输入

输入两个整数A和N

输出

输出方案数,对1e9+7 求余。

样例

Input#1

10 2

Output#1

15

Input#2

111 11

Output#2

184432

Hint

对于30%的数据,A的范围[\(1,100\)],N的范围[\(1,10\)];

对于70%的数据,A的范围[\(1,10^9\)];

对于100%的数据,A的范围[\(1,10^{12}\)],N的范围[\(1,100\)];

题解

题面给的是一个逐渐上升的连续整数序列,一开始以为有什么性质,但最后做法好像都是状压dp,所以就看成一个普通序列来做就行了,可能TC的题输入太多不方便??。

30pts

对于30%数据,由于n的范围不大,数字位数也不多,可以直接暴力枚举每个数删除哪些位。

先预处理一个数组\(sum[i][sta]\),表示第i位的状态为\(sta\)时的值(二进制,0表示删除,1表示保留)。例如第i个数字为123时,\(sum[i][3(11)]=23\),\(sum[i][7(111)]=123\)。

枚举用dfs实现。总的时间复杂度为\(O({2^{3}}^n)\)。加上一些剪枝记忆化,可以跑过。

70pts

把dfs改成动态规划转移即可。倒推。

数字位数最多为9,用二进制位表示每一种删除方案。

定义状态\(dp[i][sta]\)表示现在已经决策完第\(i..n+1\)个数字了,且第i个数字的状态为\(sta\)(二进制位,0表示删除,1表示保留)。

转移的话只要按上面的dfs改一改就好了。大致思路是,仍然先预处理上面的sum数组,然后枚举第i位,枚举这个数字的状态j,枚举上一个数字的状态k,如果\(sum[i][j]<=sum[i+1][k]\)则\(dp[i][j]+=dp[i+1][k]\)。

时间复杂度为\(O(n\cdot 2^9 \cdot 2^9)\)。如果当数字上限增加到1e12时就跑不动了。

100pts

根据条件\(sum[i][j]<=sum[i+1][k]\)很容易想到用前缀和/后缀和去优化,免去枚举第三层k。

但由于\(sum\)并非递增的,所以还得排个序,最后求和时二分一下第一个大于等于\(sum[i][j]\)的位置k,使得\(sum[i][j]<=sum[i+1][k]\)。

注意细节。

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=103;
ll A,a[N],sum[N][4100],dp[N][4100],tot[N][4100];
int n,num[N][14],len[N];
ll pw[14]; inline void Do(ll &x,ll y){
x+=y;
if(x>=mod)x-=mod;
}
int main(){
scanf("%lld%d",&A,&n);
register int i,j,k; pw[0]=1;
for(i=1;i<=12;++i)pw[i]=pw[i-1]*10; for(i=0;i<=n;++i)a[i+1]=A+1ll*i; for(i=1;i<=n+1;++i){
ll o=a[i];
while(o){
num[i][len[i]++]=o%10;
o/=10;
}
}
for(i=1;i<=n+1;++i){
for(j=0;j<(1<<len[i]);++j){
int cnt=0;
for(k=0;k<len[i];++k)if((1<<k)&j){
sum[i][j]+=1ll*pw[cnt]*num[i][k];
++cnt;
}
}
} for(int i=1;i<=n+1;i++)sort(sum[i]+1,sum[i]+(1<<len[i])); for(i=1;i<(1<<len[n+1]);++i)dp[n+1][i]=1;
for(j=(1<<len[n+1])-1;j>=1;j--)tot[n+1][j]=(tot[n+1][j]+dp[n+1][j]+tot[n+1][j+1])%mod; for(i=n;i>=1;i--){//当前轮
for(j=1;j<(1<<len[i]);++j){
ll nowj=sum[i][j];
int o=lower_bound(sum[i+1]+1,sum[i+1]+(1<<len[i+1]),nowj)-sum[i+1];
// cout<<"i:"<<i<<" nowj:"<<nowj<<" o:"<<o<<" sumk:"<<sum[i+1][o]<<endl;
// cout<<"now add:"<<tot[i+1][o]<<endl;
Do(dp[i][j],tot[i+1][o]);
}
for(j=(1<<len[i])-1;j>=1;j--)tot[i][j]=(tot[i][j]+(tot[i][j+1]+dp[i][j])%mod)%mod;
tot[i][0]=tot[i][1];
} ll ans=0;
for(i=1;i<(1<<len[1]);++i)if(dp[1][i])Do(ans,dp[1][i]);
printf("%lld\n",(ans+mod)%mod);
}

update:内存的优化(dp的第一维可以滚动,或者直接去掉改一下转移顺序)。但是由于n比较小没什么必要。

T2988 删除数字【状压Dp+前缀和优化】的更多相关文章

  1. CF917C Pollywog —— 状压DP + 矩乘优化

    C. Pollywog 题目描述 原题题目链接.题目大意为:有$x$只蝌蚪,在$n$个石头中的最左端的$x$个石头上,这$n$个石头是在同一直线上的.每一次只能最左边的一个蝌蚪进行跳跃,并且只能跳$1 ...

  2. 你必须知道的基本位运算技巧(状压DP、搜索优化都会用到)

    一. 位操作基础 基本的位操作符有与.或.异或.取反.左移.右移这6种,它们的运算规则如下所示: 符号 描述 运算规则 & 与 两个位都为1时,结果才为1 | 或 两个位都为0时,结果才为0 ...

  3. 状压DP复习笔记

    前言 复习笔记第4篇.CSP RP++. 引用部分为总结性内容. 0--P1433 吃奶酪 题目链接 luogu 题意 房间里放着 \(n\) 块奶酪,要把它们都吃掉,问至少要跑多少距离?一开始在 \ ...

  4. 「PKUSC2018」最大前缀和(状压dp)

    前言 考试被\(hyj\)吊着打... Solution 考虑一下如果前缀和如果在某一个位置的后面的任意一个前缀和都<=0,肯定这就是最大的. 然后这样子就考虑左右两边的状压dp,然后就好了. ...

  5. Loj 6433. 「PKUSC2018」最大前缀和 (状压dp)

    题面 Loj 题解 感觉挺难的啊- 状压\(dp\) 首先,有一个性质 对于一个序列的最大前缀和\(\sum_{i=1}^{p} A[i]\) 显然对于每个\(\sum_{i=p+1}^{x}A[i] ...

  6. BZOJ_5369_[Pkusc2018]最大前缀和_状压DP

    BZOJ_5369_[Pkusc2018]最大前缀和_状压DP Description 小C是一个算法竞赛爱好者,有一天小C遇到了一个非常难的问题:求一个序列的最大子段和. 但是小C并不会做这个题,于 ...

  7. 【洛谷5369】[PKUSC2018] 最大前缀和(状压DP)

    点此看题面 大致题意: 对于一个序列,求全排列下最大前缀和之和. 状压\(DP\) 考虑如果单纯按照题目中对于最大前缀和的定义,则一个序列它的最大前缀和是不唯一的. 为了方便统计,我们姑且规定,如果一 ...

  8. FJNU Fang G and his Friends(状压DP)题解

    Description     众所周知,fang G 有很多小伙伴,有一天,Fang G 打算带他们去玩有趣的游戏OOXX,这个游戏需要分成两组,有趣的是,每个人互相之间都有一个满意度,大家都想和自 ...

  9. 【BZOJ3195】[Jxoi2012]奇怪的道路 状压DP

    [BZOJ3195][Jxoi2012]奇怪的道路 Description 小宇从历史书上了解到一个古老的文明.这个文明在各个方面高度发达,交通方面也不例外.考古学家已经知道,这个文明在全盛时期有n座 ...

随机推荐

  1. Java 几种队列区别的简单说明

    前言 队列,字面意思就可以明白. 是一种线性的数据暂存与管理工具. 也可以让各种业务功能进行逐个的队列运行. 此篇博客只说明一下Java有几种队列 未阻塞和阻塞队列的区别 未阻塞: 1.未阻塞的队列在 ...

  2. CSIC_716_20191113【装饰器进阶以及迭代器】

    装饰器的进阶主要包含叠加装饰器和有参装饰器 叠加装饰器:在一个被装饰的对象中,添加多个装饰器. 为什么要用叠加装饰器的原因:    -每一个新的功能都应该写一个新的装饰器,否则会导致,代码冗余,结构不 ...

  3. CSIC_716_20191108【文件的操作,以及彻底解决编码问题的方案】

    关于编码的问题: 在平时编写代码,涉及到打开文件时,常常遇到字符编码的报错, 通过总结,得出以下规律  如果在操作过程中涉及到调用文本文档,一定要在文本文档开头申明编码方式(# coding:XXXX ...

  4. jmeter做http请求时报错

    在发帖时候发现请求不成功,在察看结果树的响应数据中提示:“”抱歉,您的请求来路不正确或表单验证串不符,无法提交“” 重复看了多次请求,发现Implementation这个地方选择HttpClient3 ...

  5. 初识Qgis

    折腾了一天,qgis终于能在跟了自己8年的本本上顺利打开了,官网先后下载了3.8和3.4版本的都出现了同样的问题,"could not load qgis_app.dll",goo ...

  6. 配置文件一mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  7. Windows mkdir

    创建目录. MKDIR [drive:]pathMD [drive:]path 如果命令扩展被启用,MKDIR 会如下改变: 如果需要,MKDIR 会在路径中创建中级目录.例如: 假设 \a 不存在, ...

  8. SGI STL rope

    rope实现的接口可以参考这里. rope是可伸缩的string实现: 它们被设计为用于把string看作一个整体的高效操作 . 比如赋值.串联和子串的操作所花的时间差不多不依赖字符串的长度.与C的字 ...

  9. System.Configuration.ConfigurationManager.cs

    ylbtech-System.Configuration.ConfigurationManager.cs 1.程序集 System.Configuration, Version=4.0.0.0, Cu ...

  10. sql stuff拼接字符串的用法

    要把图2显示成图1的方法:要用到stuff函数,并且图1显示的时间有所截断. 图2sql,只是很普通的sql ), SKSJ, )=' order by SKSJ 图1sql,用了stuff拼接 ), ...