2^k进制数[NOIP2006]

本文探讨使用动态规划(DP)算法解决特定进制数转换问题,详细解释了状态转移方程的推导和优化过程,重点在于理解并实现算法以解决实际问题。
算法:DP

一开始这道题看得我蒙蒙的,看了半天想到了递推,无奈状态表示对了但是方程写错了。后来看了题解才发现并不是很难,一言蔽之,还是爱的不够啊~

总的来说思路还算是有的,设f[i,j]表示2^k进制数长度为i位,最高位是j的方案数,则很容易的得出f[i,j]=f[i-1,j+1]+f[i-1,j+2]+...+f[i-1,2^k-1],通过观察f[i-1,j+2]+...+f[i-1,2^k-1]不难看出,这实际上就是f[i,j+1],因此我们不必累加前面的所有那么多项的式子,原式可以化简为f[i,j]=f[i-1,j+1]+f[i,j+1]。
按照以上的那个式子,我们就可以倒序的求解了。
另外要特殊注意的是,最高位,即长度为m mod n,它的取值范围只存在与1~2^(n mod m)-1之中,而不同于其它位的长度为1~2^k-1,但是如此以来,我们会漏掉2^(m mod n)~2^k-1这些状态,而由上面的推导可知,前面的状态是由后面的状态推出来的,因此我们要过滤一下状态,对于求最高位,只有在j<=2^(m mod n)-1时才进行累加。

在优化方面,考虑用8位高精度使用的内存较高,因此采用滚动数组进行优化。

program digital;

const
 maxn=512;
 cifang:array [0..10] of longint=(1,2,4,8,16,32,64,128,256,512,1024);
 
type
 arr=array [0..50] of int64;

var
 maxlen,n,m:longint;
 f:array [0..1,0..maxn] of arr;
 ans:arr;
 
procedure init;
var
 i:longint;
begin
 readln(n,m);
 maxlen:=m div n;
 for i:=cifang[n]-1 downto 1 do
  begin
   f[0,i,0]:=1;
   f[0,i,1]:=1;
  end;
 ans[0]:=1;
 ans[1]:=0;
end;

function HPP(x,y:arr):arr;
var
 i,len,t:longint;
begin
 t:=0;
 fillchar(HPP,sizeof(HPP),0);
 if x[0]>=y[0] then len:=x[0] else len:=y[0];
 HPP[0]:=len; 
 for i:=1 to len do 
  begin
   HPP[i]:=x[i]+y[i]+t;
   t:=HPP[i] div 1000000000;
   HPP[i]:=HPP[i] mod 1000000000;
  end;
 if t>0 then
  begin
   inc(HPP[0]);
   HPP[HPP[0]]:=t;
  end;
 while (HPP[HPP[0]]=0) and (HPP[0]>1) do dec(HPP[0]); 
end;

procedure main;
var
 i,j,t:longint;
begin
 {先处理不是最高位的位置。}
 for i:=1 to maxlen-1 do
  begin
   t:=i mod 2;
   for j:=cifang[n]-1 downto 1 do
    begin
     f[t,j]:=HPP(f[1-t,j+1],f[t,j+1]);
     ans:=HPP(ans,f[t,j]);
    end;
  end;
 t:=maxlen mod 2;
 {处理最高位+特殊限制。}
 if m mod n>0 then
  begin
   for j:=cifang[n]-1 downto 1 do
    begin
     f[t,j]:=HPP(f[1-t,j+1],f[t,j+1]);
     if j<=cifang[m mod n]-1 then ans:=HPP(ans,f[t,j]);   
    end;
  end;
end;

procedure print(x:arr);
var
 i:longint;
begin
 write(x[x[0]]);
 for i:=x[0]-1 downto 1 do
  begin
   if x[i]<100000000 then write(0);
   if x[i]<10000000 then write(0);
   if x[i]<1000000 then write(0);
   if x[i]<100000 then write(0);
   if x[i]<10000 then write(0);
   if x[i]<1000 then write(0);
   if x[i]<100 then write(0);
   if x[i]<10 then write(0);
   write(x[i]);
  end;
 writeln;
end;

begin
 assign(input,'digital.in'); reset(input);
 assign(output,'digital.out'); rewrite(output);
 
 init;
 main;
 print(ans);
 
 close(input); close(output);
end.



2^k进制数 时间限制:1.0s 内存限制:256.0MB 代码提交间隔:5分钟(现在可以提交) 输入文件名:digital.in 输出文件名:digital.out 试题来源:NOIP 2006 提高组 问题描述   设r是个2^k 进制数,并满足以下条件:   (1)r至少是个2位的2^k 进制数。   (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。   (3)将r转换为2进制数q后,则q的总位数不超过w。   在这里,正整数k(1≤k≤9)和w(k<w≤30000)是事先给定的。   问:满足上述条件的不同的r共有多少个?   我们再从另一角度作些解释:设S是长度为w 的01字符串(即字符串S由w个“0”或“1”组成),S对应于上述条件(3)中的q。将S从右起划分为若干个长度为k的段,每段对应一位2^k进制的数,如果S至少可分成2段,则S所对应的二进制数又可以转换为上述的2^k进制数r。   例:设k=3,w=7。则r是个八进制数2^3=8)。由于w=7,长度为7的01字符串按3位一段分,可分为3段(即1,3,3,左边第一段只有一个二进制位),则满足条件的八进制数有:   2位数:高位为1:6个(即12,13,14,15,16,17),高位为2:5个,…,高位为6:1个(即67)。共6+5+…+1=21个。   3位数:高位只能是1,第2位为2:5个(即123,124,125,126,127),第2位为3:4个,…,第2位为6:1个(即167)。共5+4+…+1=15个。   所以,满足要求的r共有36个。 输入格式   输入文件digital.in只有1行,为两个正整数,用一个空格隔开:   k W 输出格式   输出文件digital.out为1行,是一个正整数,为所求的计算结果,即满足条件的不同的r的个数(用十进制数表示),要求最高位不得为0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。   (提示:作为结果的正整数可能很大,但不会超过200位) 样例输入 3 7 样例输出 36
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值