博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2^k进制数 vijos1315 NOIP2006提高组T4
阅读量:6077 次
发布时间:2019-06-20

本文共 5415 字,大约阅读时间需要 18 分钟。

 

题面在最下方。

从题意中可以获取灵感:k与w是有关系的。

当这个2^k进制数转化为2进制时,原来的每一位(可以相对于十进制中的每一位来理解)都对应了二进制数中长为k的一个区段。

举个栗子,对于一个16(2^4)进制的数 ABCD (即 10 11 12 13)

打开windows自带的计算器就能看到:,其中 A对应二进制下的1010,B对应1011,以此类推。

所以这就体现出了阶段性的特点,可以考虑采用DP解答。 

首先要做的准备工作:

根据题意“在2^k进制下的这个数的位数要大于等于2,数字严格上升”,所以不可能有任何有效位取0的情况(可以有前导零)。

设当前推导位(第i位)取值范围为[1,maxx],令x=w%n,对于maxx讨论如下:

若 x==0 , 则所有位的取值范围都是[1,(1<<k)-1]。

若 x!=0 ,则在最高位上可取的值为 [1,(1<<x)-1],其他位是[1,(1<<k)-1]。

从低位向高位推导,令 F[i][j] 是第i位上放数字j后满足条件的总方案数

则转移方程为 F[i][j]=∑F[i-1][k](j<k<=maxx)

同时由于w限制的是最大位数而非必需位数,所以在每次转移过后,都要 ans+=F[i][j]

 

如何优化?

第一个简单的优化,每一次状态转移的求和可以用后缀数组进行优化。

第二个优化是可以用滚动数组的思想,把F[i][j]优化为一维的F[i],具体可看代码实现。

其他要说的

高精度的模版是我从网上扒下来的,至今不会写高精度(逃)

 

1 #include
2 #include
3 #include
4 #include
5 using namespace std; 6 template
inline void read(T &_a){ 7 bool f=0;int _ch=getchar();_a=0; 8 while(_ch<'0' || _ch>'9'){
if(_ch=='-')f=1;_ch=getchar();} 9 while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();} 10 if(f)_a=-_a; 11 } 12 const int maxn = 300; 13 14 struct bign{ 15 int d[maxn], len; 16 void clean() { while(len > 1 && !d[len-1]) len--; } 17 18 bign() { memset(d, 0, sizeof(d)); len = 1; } 19 bign(int num) { *this = num; } 20 bign(char* num) { *this = num; } 21 bign operator = (const char* num){ 22 memset(d, 0, sizeof(d)); len = strlen(num); 23 for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0'; 24 clean(); 25 return *this; 26 } 27 bign operator = (int num){ 28 char s[20]; sprintf(s, "%d", num); 29 *this = s; 30 return *this; 31 } 32 33 bign operator + (const bign& b){ 34 bign c = *this; int i; 35 for (i = 0; i < b.len; i++){ 36 c.d[i] += b.d[i]; 37 if (c.d[i] > 9) c.d[i]%=10, c.d[i+1]++; 38 } 39 while (c.d[i] > 9) c.d[i++]%=10, c.d[i]++; 40 c.len = max(len, b.len); 41 if (c.d[i] && c.len <= i) c.len = i+1; 42 return c; 43 } 44 bign operator - (const bign& b){ 45 bign c = *this; int i; 46 for (i = 0; i < b.len; i++){ 47 c.d[i] -= b.d[i]; 48 if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--; 49 } 50 while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--; 51 c.clean(); 52 return c; 53 } 54 bign operator * (const bign& b)const{ 55 int i, j; bign c; c.len = len + b.len; 56 for(j = 0; j < b.len; j++) for(i = 0; i < len; i++) 57 c.d[i+j] += d[i] * b.d[j]; 58 for(i = 0; i < c.len-1; i++) 59 c.d[i+1] += c.d[i]/10, c.d[i] %= 10; 60 c.clean(); 61 return c; 62 } 63 bign operator / (const bign& b){ 64 int i, j; 65 bign c = *this, a = 0; 66 for (i = len - 1; i >= 0; i--) 67 { 68 a = a*10 + d[i]; 69 for (j = 0; j < 10; j++) if (a < b*(j+1)) break; 70 c.d[i] = j; 71 a = a - b*j; 72 } 73 c.clean(); 74 return c; 75 } 76 bign operator % (const bign& b){ 77 int i, j; 78 bign a = 0; 79 for (i = len - 1; i >= 0; i--) 80 { 81 a = a*10 + d[i]; 82 for (j = 0; j < 10; j++) if (a < b*(j+1)) break; 83 a = a - b*j; 84 } 85 return a; 86 } 87 bign operator += (const bign& b){ 88 *this = *this + b; 89 return *this; 90 } 91 92 bool operator <(const bign& b) const{ 93 if(len != b.len) return len < b.len; 94 for(int i = len-1; i >= 0; i--) 95 if(d[i] != b.d[i]) return d[i] < b.d[i]; 96 return false; 97 } 98 bool operator >(const bign& b) const{
return b < *this;} 99 bool operator<=(const bign& b) const{
return !(b < *this);} 100 bool operator>=(const bign& b) const{
return !(*this < b);} 101 bool operator!=(const bign& b) const{
return b < *this || *this < b;} 102 bool operator==(const bign& b) const{
return !(b < *this) && !(b > *this);} 103 104 string str() const{ 105 char s[maxn]={}; 106 for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0'; 107 return s; 108 } 109 };110 111 int k,w,deg,maxx;112 bign f[1<<10],sum[1<<10],ans;113 114 int main()115 {116 read(k); read(w);117 deg=(1<
=k)120 {121 w-=k;122 if(w>=k) maxx=deg;123 else maxx=(1<
View Code

 

 

描述

设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”m组成),S对应于上述条件(3)中的q。将S从右起划分为若干个长度为k 的段,每段对应一位2^k进制的数,如果S至少可分成2段,则S所对应的二进制数又可以转换为上述的2^k 进制数r。

例:设k=3,w=7。则r是个八进制数(23=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个。

格式

输入格式

输入文件只有1行,为两个正整数,用一个空格隔开:

k W

输出格式

输出文件为1行,是一个正整数,为所求的计算结果,即满足条件的不同的r的个数(用十进制数表示),要求最高位不得为0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。

(提示:作为结果的正整数可能很大,但不会超过200位)

样例1

样例输入1

3 7

样例输出1

36

限制

1s

转载于:https://www.cnblogs.com/jaywang/p/7689753.html

你可能感兴趣的文章
python3-staticmethod与classmethod
查看>>
【原创】C#搭建足球赛事资料库与预测平台(6) 赔率数据表设计2
查看>>
NET3.0+中使软件发出声音[整理篇]<转>
查看>>
Java并发编程:Callable、Future和FutureTask
查看>>
[spark][python]Spark map 处理
查看>>
三层架构实战篇 下
查看>>
A*算法入门
查看>>
Console-Un-算法[运算符]-取一个整数a从右端开始的4~7位
查看>>
制作Java安装程序
查看>>
js中的函数参数问题
查看>>
C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能
查看>>
Android Studio 常用快捷键 for mac
查看>>
51 Nod 1791 合法括号子段【分治+字符串】
查看>>
SignalR---服务端
查看>>
Android App data write as file data with synchronous Demo
查看>>
Java 3D 1.5.1 Released
查看>>
6.3. Office Software
查看>>
3.6. FAQ
查看>>
jquery中dom元素的attr和prop方法的理解
查看>>
使用 github.io 免费建站
查看>>