因数小于16的正整数拆分方案:一个有趣的dp
来源:互联网 发布:发表小说的软件 编辑:程序博客网 时间:2024/06/06 08:44
“灰常灰常”有趣的dp;
给定一个高精数,将这个高精数分解成若干个不大于16的因数的幂的积,求方案数;
也就是把s分解为:a1^K1 * a2^k2 * a3^k3......,其中a<=16;
由于给出数字实在太大了,考场上以为是个矩乘或母函数(TAT)......
这道题的dp也算隐藏的比较深;
首先将s分解质因数:可以知道,如果有大于16的质因数,那么方案数为0,而如果有11,13的质因数,那么他们 对答案毫无贡献,11和13只能单独存在。
而剩下的只有2,3,5,7,可以构成的合数有4,6,8,9,10,12,14,15;
明显只用2,3可以拼出4,6,8,9,可以枚举有多少个2和3是拼成4,6,8,9这些数的,此时,如果单独拼7的个数确定,那么所有的数都是确定的了(枚举的2,且已知7,可以推出有多少个14,从而推出10,枚举3可以推出15的个数,最后推出5的个数)。
因此可以先dp:用i个2和j个3 一起拼,拼成4,6,8,9的方案数,然后看有多少个7可以单独放出,统计答案。
贴代码:
program decomposition;uses math;const mo=1000000000+9;type arr=array[0..3000]of longint;var s:ansistring; b,a:arr; tot,m2,m3:array[0..20]of longint; bj:array[0..20]of boolean; f:array[0..5000,0..5000]of longint; b2,b3,now,k,i,j:longint; ans,l,r,tmp:int64;procedure inf;begin assign(input,'decomposition.in'); assign(output,'decomposition.out'); reset(input);rewrite(output);end;procedure ouf;begin close(input);close(output);end;procedure init;begin readln(s); for i:=length(s) downto 1 do begin inc(a[0]); a[a[0]]:=ord(s[i])-ord('0'); end;end;function arrdiv(x:longint):boolean;var i:longint;begin move(a[1],b[1],a[0]*4); b[0]:=a[0]; for i:=b[0] downto 2 do b[i-1]:=b[i-1]+(b[i] mod x)*10; if b[1] mod x =0 then exit(true) else exit(false);end;operator /(var a:arr;b:longint)c:arr;var i:longint;begin move(a[1],c[1],a[0]*4); c[0]:=a[0]; for i:=c[0] downto 1 do begin c[i-1]:=c[i-1]+(c[i] mod b)*10; c[i]:=c[i] div b; end; while (c[c[0]]=0) and (c[0]>1) do dec(c[0]);end;procedure work(x:longint);begin while arrdiv(x) do begin inc(tot[x]); a:=a / x; end;end;procedure prepare;begin work(2); work(3);work(5); work(7); work(11); work(13); if (a[0]>1)or ((a[0]=1) and (a[1]>1)) then begin write(0); ouf; halt; end; for i:=1 to 16 do begin now:=i; while now mod 2=0 do begin now:=now div 2; inc(m2[i]); end; while now mod 3=0 do begin now:=now div 3; inc(m3[i]); end; if now>1 then bj[i]:=false else bj[i]:=true; end; fillchar(f,sizeof(f),0); f[0,0]:=1; for k:=2 to 16 do if bj[k] then for i:=m2[k] to tot[2] do for j:=m3[k] to tot[3] do if f[i-m2[k],j-m3[k]]>0 then f[i,j]:=(f[i,j]+f[i-m2[k],j-m3[k]]) mod mo;end;procedure main;begin for b2:=0 to tot[2] do for b3:=0 to tot[3] do if f[b2,b3]>0 then begin l:=max(max(0,tot[7]+b2-tot[2]),tot[7]+b2+b3-tot[2]-tot[3]); r:=min(tot[7],tot[5]+tot[7]-tot[2]-tot[3]+b2+b3); tmp:=f[b2,b3]; if r>=l then ans:=(ans+(r-l+1)*tmp) mod mo; end; writeln(ans);end;begin inf; init; prepare; main; ouf;end.
- 因数小于16的正整数拆分方案:一个有趣的dp
- 统计正整数n的因数个数
- 求正整数n的因数之和
- 判断一个小于5位的正整数是几位数
- 长度小于3的正整数
- 将一个正整数拆分成若干个互不相同的正整数且乘积最大(JS)
- 将一个正整数拆分成若干个互不相同的正整数且乘积最大(JS)
- 求一个整数的因数
- 求一个整数的因数
- 求小于正整数N的所有质数
- 一道笔试题 题目是这样的:判断一个小于1000的正整数是否为素数。
- 小于等于n的正整数相加等于m的一个算法
- 输出所有小于等于n(n为一个大于2的正整数)的素数
- 求一个小于10的正整数的n次方,n很大
- 输入一个小于360的正整数,求它的正弦和余弦
- 输入任意一个大于2的正整数n,输出所有小于等于n的素数
- 正整数n的k拆分问题
- [算法]将一个正整数拆分成若干个正整数的和,输出所有的结果不重复
- poj2485-最小生成树(prime+kruskal)
- struts2源码浅析(三)
- 冬季篮球赛
- jsp 标签、域
- 10723 - Cyborg Genes
- 因数小于16的正整数拆分方案:一个有趣的dp
- Android应用程序线程消息循环模型分析
- 批处理
- struts2源码浅析(四)
- HDFS集群的启动(1)——概述
- jsp标准标签库整理
- ubuntu 11.04下android开发环境的搭建!
- spring的线程安全问题
- Google Reader 恢复紧凑布局CSS修正