2021.10.29 数位dp
2021.10.29 数位dp
1.数字计数
我们先设数字为ABCD
看A000,如果我们要求出它所有数位之和,我们会怎么求?
鉴于我们其实已经求出了0到9,0到99,0到999。。。上所有数字个数(f[i],且没有考虑前导0)我们何不把这个A000看成0000到1000到2000...A000对于不考虑首位每一个式子的数字的出现个数为 \(A*f[3]\)。加上首位出现也就是小于A每一个数都出现了\(10^3\)次,再加上,我们就把A000处理完了。
这样你以为就把第一位处理完了?不不不,首位A还出现了BCD+1次呢,也就是从A000~ABCD,这个A还出现了BCD+1次,所以再加上这些才行呢。那么你发现,我们成功把首位代表的所有数字个数求出来了,剩下的求解与A完全没有任何关系,只是BCD的求解,于是我们发现我们已经把一个大问题,化成了一个个小问题,也即是,对于一个这样n位的数,把他一位位的分离开来。
当然你还需要处理前导0你会发现前导0一定是\(0001,0002\cdots0012,0013\cdots0101,0102\cdots0999\)这样的数,一共出现了\(10*(i-1)+10*(i-2)+\cdots+10\) (i表示数字位数),让0的统计减去这个值,那么恭喜你这道题做完了。
来自[题解 P2602 【ZJOI2010]数字计数】 - moye到碗里来 的博客 - 洛谷博客 (luogu.com.cn)
练习题:
[P2602 ZJOI2010]数字计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
运用前缀和的想法,把从a到b拆分为从1到b减去从1到a-1的结果
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=15;
int a,b,f[N],ten[N],numa[N],numb[N],cnt[N];
inline void solve(int x,int *num){
int top=0;
while(x){
cnt[++top]=x%10;
x/=10;
}
for(int i=top;i>=1;i--){
for(int j=0;j<10;j++)num[j]+=f[i-1]*cnt[i];
for(int j=0;j<cnt[i];j++)num[j]+=ten[i-1];
int js=0;
for(int j=i-1;j>=1;j--)js=js*10+cnt[j];
num[cnt[i]]+=js+1;
num[0]-=ten[i-1];
}
}
int main(){
ios::sync_with_stdio(false);
cin>>a>>b;
ten[0]=1;
for(int i=1;i<=12;i++)
f[i]=f[i-1]*10+ten[i-1],ten[i]=ten[i-1]*10;
solve(a-1,numa);solve(b,numb);
for(int i=0;i<10;i++)cout<<numb[i]-numa[i]<<" ";
return 0;
}
PS:数位dp是对每一位上的数字分开进行处理。如数字ABCD,先处理010010002000……A000,然后处理BCD,把BCD拆开处理,先处理0B00,再处理0C0,再处理D,完结撒花
[P2657 SCOI2009] windy 数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
// https://www.luogu.com.cn/discuss/246065
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=15;
int a,b,f[N][N],num[N],len;
inline int calc(int x){
memset(num,0,sizeof(num));
len=0;
while(x){
num[++len]=x%10;
x/=10;
}
int ans=0;
for(int i=1;i<len;i++)
for(int j=1;j<10;j++)//这里不能有前导零,因为是每次枚举不同长度的最高位
ans+=f[i][j];
for(int i=1;i<num[len];i++)ans+=f[len][i];
for(int i=len-1;i>=1;i--){
for(int j=0;j<num[i];j++)//这里可以有前导零,因为这里是枚举在已经有前面固定的几位后剩下长度的为高位,而不是原数的最高位,可以有前导零
if(abs(num[i+1]-j)>=2)ans+=f[i][j];
if(abs(num[i]-num[i+1])<2)break;
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
for(int i=0;i<10;i++)f[1][i]=1;
for(int i=2;i<=10;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
if(abs(j-k)>=2)f[i][j]+=f[i-1][k];
cin>>a>>b;
cout<<calc(b+1)-calc(a);
return 0;
}
区间DP
[P2890 USACO07OPEN]Cheapest Palindrome G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
开始把区间dp写成了求lcs+删字母或加字母,于是10分……其余RE,why?!
10分代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=2010;
//string s,t;
char s[N],t[N];
int m,n,f[N],id[N][N],fin[N],top,a[N],val[N],minn;
map<int,char>mapi;
inline int find(int x){
int L=1,R=top,mid;
while(L<R){
mid=(L+R)>>1;
if(fin[mid]<=x)L=mid+1;
else R=mid;
}
return L;
}
int main(){
ios::sync_with_stdio(false);
cin>>m>>n;
//cin>>s;
//t=s;reverse(t.begin(),t.end());
scanf("%s",s);
memcpy(t,s,sizeof(s));
reverse(t,t+strlen(t));
//cout<<t<<endl;
for(int i=1;i<=n;i++){
int x=s[i-1]-'a'+1;
++id[x][0];
id[x][id[x][0]]=i;
//cout<<id[x][id[x][0]]<<" ";
mapi[i]=s[i-1];
}
//cout<<endl;
for(int i=1;i<=m;i++)id[i][0]=0;
for(int i=1;i<=n;i++){
int x=t[i-1]-'a'+1;
++id[x][0];
a[i]=id[x][id[x][0]];
//cout<<a[i]<<" ";
}
//cout<<endl;
for(int i=1;i<=m;i++)id[i][0]=0;
cout<<" Case 1"<<endl;
fin[1]=a[1];top=1;++id[mapi[a[1]]-'a'+1][0];
cout<<" Case 2"<<endl;
for(int i=2;i<=n;i++)
if(fin[top]<=a[i])fin[++top]=a[i],++id[mapi[a[i]]-'a'+1][0],cout<<i<<endl;
else{
int x=find(a[i]);
cout<<i<<" "<<x<<" "<<mapi[fin[x]]<<endl;
--id[mapi[fin[x]]-'a'+1][0];
fin[x]=a[i];
++id[mapi[a[i]]-'a'+1][0];
}
for(int i=1;i<=top;i++)cout<<fin[i]<<" ";cout<<endl;
//for(int i=1;i<=top;i++)cout<<mapi[fin[i]]<<" ";cout<<endl;
for(int i=1,j=1;i<=m;i++){
char x;
int u,v;
cin>>x>>u>>v;
int xi=x-'a'+1;
if(mapi[fin[j]]==x)minn+=u*id[xi][0],++j;
val[xi]=min(u,v);//0 add 1 delete
}
//cout<<"minn "<<minn<<endl;
int ans=0;
for(int i=1,j=1;i<=n;){
//cout<<i<<" "<<a[i]<<" "<<j<<" "<<fin[j]<<" "<<ans<<endl;
if(a[i]==fin[j])++i,++j;
else ans+=val[mapi[a[i]]-'a'+1],++i;
}
//cout<<"ans "<<ans<<endl;
cout<<min(minn,ans);
return 0;
}
100分代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=2010;
int n,m,f[N][N],val[N];
char s[N];
int main(){
//ios::sync_with_stdio(false);
//呵呵了,洛谷上加上这一行直接挂了
cin>>m>>n;
scanf("%s",s+1);
for(int i=1;i<=m;i++){
char x;
int u,v;
cin>>x>>u>>v;
val[x-'a']=min(u,v);
}
memset(f,0x3f3f3f3f,sizeof(f));
for(int i=1;i<=n;i++){
f[i][i]=0;
if(s[i]==s[i+1])f[i][i+1]=0;
}
for(int len=0;len<=n;len++)
for(int i=1;i+len<=n;i++){
int j=i+len;
int u=s[i-1]-'a',v=s[j+1]-'a';
if(u==v)f[i-1][j+1]=min(f[i][j],f[i-1][j+1]);
f[i-1][j]=min(f[i-1][j],f[i][j]+val[u]);
f[i][j+1]=min(f[i][j+1],f[i][j]+val[v]);
}
cout<<f[1][n];
return 0;
}
普通DP
[P1310 NOIP2011 普及组] 表达式的值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题意:
运算的优先级是:
- 先计算括号内的,再计算括号外的。
- “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。
现给定一个未完成的表达式,例如_+(*),请你在横线处填入数字00或者11 ,请问有多少种填法可以使得表达式的值为00。
分析:
思路不会,只会状态转移。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
#define int long long
const int N=2e5+10;
const int mod=1e4+7;
int n,m,top=1;
string si;
stack<char>s;
struct node{
int zero,one;
}ans[N];
inline void solve(char ch,node &a,node &b){
if(ch=='+'){
a.one=(a.one*b.one%mod+a.zero*b.one%mod+a.one*b.zero%mod)%mod;
a.zero=a.zero*b.zero%mod;
}else{
a.zero=(a.zero*b.zero%mod+a.one*b.zero%mod+a.zero*b.one%mod)%mod;
a.one=(a.one*b.one)%mod;
}
}
signed main(){
cin>>n;
cin>>si;
si+=')';
//cout<<si<<endl;
ans[1].one=ans[1].zero=1;
s.push('(');
for(int i=0;i<=n;i++){
//cout<<i<<endl;
if(si[i]=='(')s.push('(');
else if(si[i]==')'){
for(;s.top()!='(';s.pop(),top--)
solve(s.top(),ans[top-1],ans[top]);//,cout<<s.top()<<" ";cout<<endl;
s.pop();
}else{
for(;s.top()<=si[i]&&s.top()!='(';s.pop(),top--)
solve(s.top(),ans[top-1],ans[top]);//,cout<<s.top()<<" ";cout<<endl;
s.push(si[i]);
++top;
ans[top].zero=ans[top].one=1;
}
}
cout<<ans[1].zero;
return 0;
}
2021.10.29 数位dp的更多相关文章
- 2021.10.29 P1649 [USACO07OCT]Obstacle Course S(BFS)
2021.10.29 P1649 [USACO07OCT]Obstacle Course S(BFS) 题意: 给一张n*n的图,起点为A,终点为 B,求从A到B转弯次数最少为多少. 分析: 是否存在 ...
- 日常Java 2021/10/29
Java Object类是所有类的父类,也就是说Java的所有类都继承了Object,子类可以使用Object的所有方法. Object类位于java.lang 包中,编译时会自动导入,我们创建一个类 ...
- 数位dp总结
由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...
- HDU3709 Balanced Number (数位dp)
Balanced Number Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Descript ...
- bzoj 3209 bzoj1799 数位dp
3209: 花神的数论题 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2267 Solved: 1040[Submit][Status][Disc ...
- 【10.17校内测试】【二进制数位DP】【博弈论/预处理】【玄学(?)DP】
Solution 几乎是秒想到的水题叻! 异或很容易想到每一位单独做贡献,所以我们需要统计的是区间内每一位上做的贡献,就是统计区间内每一位是1的数的数量. 所以就写数位dp辣!(昨天才做了数字统计不要 ...
- 【NOI2019模拟2019.6.29】组合数(Lucas定理、数位dp)
Description: p<=10且p是质数,n<=7,l,r<=1e18 题解: Lucas定理: \(C_{n}^m=C_{n~mod~p}^{m~mod~p}*C_{n/p} ...
- Noip模拟69 2021.10.5
考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ...
- HDU 2089 不要62 (递推+暴力或者数位DP)
题意:中文题. 析:暴力先从1到1000000,然后输出就好了. 代码如下: #include <iostream> #include <cstdio> #include &l ...
随机推荐
- 爬虫系列之Scrapy框架
一 scrapy框架简介 1 介绍 (1) 什么是Scrapy? Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍.所谓的框架就是一个已经被集成了各种功能(高性能 ...
- Django项目常用的logging配置。
做开发开不开日志,以下是我在工作中写Django项目常用的logging配置. LOGGING = { 'version': 1, 'disable_existing_loggers': False, ...
- BUAA_DS_聊聊链表
幸福穿着节日的盛装欢迎你. --威廉•莎士比亚<罗密欧与朱丽叶> 1. 说在前面 大家在学数组的时候小脑瓜里有没有这样的疑惑:为什么数组必须是定长的?为什么数组开太长会编译错误?数组越界为 ...
- 数据库上云实践:使用Ora2pg进行数据库迁移
目录 概述 重要 前置条件 配置环境 Win环境配置 linux环境配置 定义ORACLE_HOME环境变量 Ora2Pg使用方法 配置文件ora2pg_table.conf 配置文件解释:Oracl ...
- Adobe AIR 应用程序图标详细描述
官方PDF文档: http://help.adobe.com/zh_CN/air/build/WS901d38e593cd1bac1e63e3d129907d2886-8000.html#WS901d ...
- 深入理解Java虚拟机-垃圾收集算法
一.判断对象是否可进行回收 1.引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是不可能再被使用的.但是主流的 ...
- spring bean 容器的生命周期是什么样的?
spring bean 容器的生命周期流程如下: 1.Spring 容器根据配置中的 bean 定义中实例化 bean. 2.Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置. 3 ...
- session与cookie的区别? 如果客户端禁止 cookie session 还能用吗?
一.session与cookie的区别 session:Session 是存放在服务器端的,类似于Session结构来存放用户数据,当浏览器 第一次发送请求时,服务器自动生成了一个Session和一个 ...
- java-web中的Filter&Listener
Filter过滤器 当访问服务器资源的时候,过滤器可以将i气你个球拦截下来,完成一些特殊的功能 过滤器的作用: 一般用于完成通用的操作,如验证登陆,统一的编码处理,敏感字符过滤.就是打游戏骂人,会出现 ...
- 玩转 React(四)- 创造一个新的 HTML 标签
在第二篇文章 <新型前端开发方式> 中有说到 React 有很爽的一点就是给我们一种创造 HTML 标签的能力,那么今天这篇文章就详细讲解下 React 是如何提供这种能力的,作为前端开发 ...