【hdu2929】【高精度+动规】CQYZ_Vijos_P2102 越大越好
2017-11-07 19:36
375 查看
【问题描述】
你的任务是用不超过n(n≤100)根火柴摆一个尽量大的,能被m(m≤3 000)整除的正整数,如图1-64所示。例如n=6和m=3,解为111。无解时输出-1。如下图所示:数字0到9,它们的火柴数量分别是:6、2、5、5、4、5、6、3、7、6。【输入格式】
若干行,每行包含两个正整数n和m。输入以n=0结束。【输出格式】
若干行,对应输入的n和m。【输入样例】
6 35 6
0
【输出样例】
111-1
【数据范围】
对于20%的数据:1<=n<=20对于50%的数据:1<=n<=30
对于100%的数据:1<=n<=100,1<=m<=3000。每个测试点最多不超过10组数据。
题解:
白书上的题解是记录当前对m取余为j的位数为i所需要的最少火柴数,这里不去管它,我要讲的是更暴力也更容易想到的状态函数设计:f(i,j)表示用i根火柴能组成的被m取模为j的最大值
设p[k]为组成k需要的火柴数,则有
f(i,j)=max{ f(i-p[k],(j-k) mod m) | 0<=k<=9 && i-p[k]>=0 }
很明显最终结果远远超过了long long 的数据范围,需要用到高精度运算
题目本身不太难,主要是在写高精度时有一些小地方需要注意
代码实现:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; //0,1,2,3,4,5,6,7,8,9 const int mo=1000000,p[]={6,2,5,5,4,5,6,3,7,6}; //压一压位,优化下计算速度 struct bign{ int z[35],len; bign(){ memset(z,0,sizeof(z)); len=1; } //最开始用的sprintf将整数转化成字符串再赋值,但显而易见太慢了 void operator=(int x){ memset(z,0,sizeof(z)); len=0; if(x==0) len=1; else while(x!=0) z[len++]=x%mo,x/=mo; } friend bool operator<(bign a,bign b){ if(a.len!=b.len) return a.len<b.len; for(int i=a.len-1;i>=0;i--) if(a.z[i]!=b.z[i]) return a.z[i]<b.z[i]; return 0; } //因为题目只涉及到加法和乘法,所以只重定义了这两个运算符 friend bign operator+(bign a,int b){ bign c=a; int len=a.len; c.z[0]+=b; for(int i=0;i<len;i++) c.z[i+1]+=c.z[i]/mo,c.z[i]%=mo; while(c.z[len]>0) c.z[len+1]+=c.z[len]/mo,c.z[len]%=mo,len++; while(len>1&&c.z[len-1]==0) len--; c.len=len; return c; } friend bign operator*(bign a,int b){ bign c; int len=a.len+15; for(int i=0;i<a.len;i++) c.z[i]+=a.z[i]*b; for(int i=0;i<len;i++) c.z[i+1]+=c.z[i]/mo,c.z[i]%=mo; while(c.z[len]>0) c.z[len+1]+=c.z[len]/mo,c.z[len]%=mo,len++; while(len>1&&c.z[len-1]==0) len--; c.len=len; return c; } void out(){ printf("%d",z[len-1]); for(int i=len-2;i>=0;i--) printf("%06d",z[i]); printf("\n"); } }d[105][3005]; int n,m; bool vis[105][3005]={0}; inline int in(){ int x=0,f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-') f=-f;ch=getchar();} while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar(); return x*f; } int main(){ bign tmp1,tmp2,ans; while(1){ n=in(); if(n==0) break; memset(vis,0,sizeof(vis)); m=in(),ans.z[0]=-1,ans.len=1; for(int k=1;k<=9;k++){ tmp1=k; if(d[p[k]][k%m]<tmp1) d[p[k]][k%m]=tmp1; vis[p[k]][k%m]=1; } for(int i=1;i<=n;i++){ for(int j=0;j<m;j++){ if(!vis[i][j]) continue; tmp1=d[i][j]*10; for(int k=0;k<=9;k++){ if(i+p[k]>n) continue; tmp2=tmp1+k; if(d[i+p[k]][(j*10+k)%m]<tmp2) d[i+p[k]][(j*10+k)%m]=tmp2; vis[i+p[k]][(j*10+k)%m]=1; } } if(vis[i][0]) if(ans<d[i][0]) ans=d[i][0]; } ans.out(); for(int i=0;i<=n;i++) for(int j=0;j<m;j++) d[i][j]=0; } return 0; }
相关文章推荐
- vijos1431[noip2007]守望者的逃离(背包动规)
- vijos1431[noip2007]守望者的逃离(背包动规)
- Vijos[1144]小胖守皇宫 树动规
- 【Uva12222】CQYZ_Vijos_P3179 山路
- VIJOS1200 高精度乘法 素数判定
- vijos循环(高精度)
- 【线段树+DFS序】CQYZ_Vijos_P3751 树上路径动态查询
- 【bzoj1592】【Usaco2008 Feb】【动态规划】CQYZ_Vijos_P1468 路面修整
- Vijos P1354 Hanoi双塔问题(动态规划,高精度)
- Cpp环境【Vijos1037】【CQYZos1391】搭建双塔
- [VIJOS-1040] 高精度乘法
- 【数学基础】CQYZ_Vijos_P3768 热身赛 Suspect
- CQYZ_Vijos_P3090 赛车游戏
- 【二分】【高精度】Vijos P1472 教主的集合序列
- 【vijos】1447 开关灯泡(高精度+特殊的技巧)
- 【计蒜客17293】【学校联考】CQYZ_Vijos_P3754 抢气球
- 【二分】【高精度】Vijos P1472 教主的集合序列
- vijos - P1223麦森数 (高精度乘法 + 分治 + python)
- Cpp环境【NOIP2003 P3】【Vijos1100】【Code[VS]1090】【CQYZOS2816】加分二叉树
- 【vijos1033】【数值/数论】【高精度乘法】整数分解(版本2)