uva 1640 两种方法 数位dp或枚举计算
来源:互联网 发布:怎么制作视频软件 编辑:程序博客网 时间:2024/05/16 12:40
对于区间计数问题,一般都是令F {i}(n)为[0,n]之间i出现的次数,再去区间相减就可以了
第一种方法:
例如 4321,分别求0-3999,4000-4299,4300-4319,4320+4321
0-3999中,最高位只出现过0,1,2,3, 对应的它出现的次数为1000(x***),其他位上每种数字出现的次数相同,都是(1000*3)/10
前导0不算,为了计算方便,先算进去,再减,不算的情况只出现在了第一次计算0-3999的时候,有多少个呢?
1000+100+10
所以我们按位从高位开始枚举,来统计各个数字出现的次数
注意 在计算10^n的时候不能用pow转换成整形来计算,会出现精度丢失的情况吗,所以自己生成一个就行了。
#include <iostream>#include <cstdio>#include <ctime>#include <cstring>#include <algorithm>#include <vector>#include <map>#include <cmath>#include <set>#include <queue>using namespace std;const int INF=1e9+1000;const double EPS = 1e-10; typedef long long ll;int a[15],b[15];int pova[17];int mpow10[10];void cal(int n,int *d){ int tmp=n; int pos=0; int c[15]; do{ c[pos++]=tmp%10; tmp/=10; }while(tmp); pos--; char s[15]; sprintf(s,"%d",n); for(int i=0;i<=pos;i++){ sscanf(s+pos-i,"%d",&pova[i]); } int k=mpow10[pos]; for(int i=pos;i>0;i--){ for(int j=0;j<c[i];j++){ d[j]+=k; for(int z=0;z<=9;z++){ d[z]+=k*i/10; } } d[c[i]]+=pova[i-1]+1; d[0]-=k; k/=10; } for(int i=0;i<=c[0];i++) d[i]++;}int main(){ //freopen("out.txt","w",stdout); //ios_base::sync_with_stdio(false); int l,r; mpow10[0]=1; for(int i=1;i<=8;i++) mpow10[i]=mpow10[i-1]*10; while(scanf("%d %d",&l,&r)&&l+r){ if(l>r) swap(l,r); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); cal(l-1,a); cal(r,b); for(int i=0;i<=9;i++) printf("%d%c",b[i]-a[i],i==9?'\n':' '); } return 0;}
其中 cnt的设置很是精妙,避免了一大堆的判定,lead用来判断枚举到该位的时候是否有前导0,。
#include <iostream>#include <cstdio>#include <ctime>#include <cstring>#include <algorithm>#include <vector>#include <map>#include <cmath>#include <set>#include <queue>using namespace std;const int INF=1e9+1000;const double EPS = 1e-10; typedef long long ll;int a[15],b[15];int digit[15];int d[15][2][15][15];int dfs(int pos,int lead,int val,int limit,int cnt){if(pos==-1){if(lead)return 1;elsereturn cnt;}if(!limit&&d[pos][lead][val][cnt]!=-1) return d[pos][lead][val][cnt];int up=limit?digit[pos]:9;int ans=0;for(int i=0;i<=up;i++){if(!lead){ans+=dfs(pos-1,0,val,limit&&i==up,cnt+(i==val));}else{if(i==0){ans+=dfs(pos-1,1,val,limit&&i==up,cnt);}else{ans+=dfs(pos-1,0,val,limit&&i==up,cnt+(i==val));}}}if(!limit) d[pos][lead][val][cnt]=ans;return ans;}void cal(int n,int *f){int pos=0;do{digit[pos++]=n%10;n/=10;}while(n);for(int i=0;i<=9;i++){f[i]=dfs(pos-1,1,i,1,0);}}int main(){//freopen("out.txt","w",stdout);//ios_base::sync_with_stdio(false);int l,r;memset(d,-1,sizeof(d));while(scanf("%d %d",&l,&r)&&l+r){if(l>r) swap(l,r);memset(a,0,sizeof(a));memset(b,0,sizeof(b));cal(l-1,a);cal(r,b);for(int i=0;i<=9;i++)printf("%d%c",b[i]-a[i],i==9?'\n':' ');}return 0;}
1 0
- uva 1640 两种方法 数位dp或枚举计算
- HDU 4722 Good Numbers 数位dp或找规律枚举 数位dp感悟
- 数位DP hdu3709 枚举
- uva 10401 数位DP
- uva 11361 数位DP
- uva fzu2019(数位dp)
- UVA 12670 数位DP
- 数位DP UVA
- hdu2089 不要62(数位dp两种做法)
- HDU2089 不要62(数位DP 两种姿势)
- HDU 2089 暴力or两种思路的数位DP
- HDU 3555 数位DP入门(两种思路)
- 数位DP-要49-基础DP-hdu3555-四种方法
- UVA 1640(数位统计)
- 两题类似的数位DP
- UVA 10712 - Count the Numbers (数位DP)
- uva 417 - Word Index(数位dp)
- uva 10712 - Count the Numbers(数位dp)
- 学习笔记
- liferay文档结构,主要是portlet 名称或路径变化后修改的配置文件
- enote笔记语言(4)(ver0.3)——“5w1h2k”分析法
- linux内核模块初始化
- 存储系统
- uva 1640 两种方法 数位dp或枚举计算
- NYOJ234吃土豆(双层动态规划)
- LintCode 54 转换字符串到整数
- NUC1937 B.函数
- 2017年第十届华中地区大学生数学建模邀请赛经典赛B题 基于通讯数据的社群聚类
- I Hate It
- HashTable和ConcurrentHashTable
- python爬虫之BeautifulSoup
- Oracle数据库如何查看当前服务器有多少个数据库?