BZOJ 1111: [POI2007]四进制的天平Wag

1111: [POI2007]四进制的天平Wag

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 223  Solved: 151
[Submit][Status][Discuss]

Description

Mary准备举办一个聚会,她准备邀请很多的人参加她的聚会。并且她准备给每位来宾准备一些金子作为礼物。为了不伤及每个人的脸面,每个人获得的金子必须相同。Mary将要用一个天平来称量出金子。她有很多的砝码,所有砝码的质量都是4的幂。Mary将金子置于左边并且将砝码置于右盘或者两个盘。她希望每次称量都使用最少的砝码。并且,他希望,每次都用不同的称量方法称出相同质量的金子。对于给定的质量n,Mary希望知道最少需要用多少个砝码可以完成称量,并且想知道用这么多个砝码一共有多少种方式进行称量。

Input

输入文件仅包含一个整数,表示Mary希望给每个人的金子的质量。(1<=n<=10^1000)

Output

输出文件仅包含一个整数,表示一共可能的称量方式对10^9的模。

Sample Input

166

Sample Output

3
样例解释
一共有三种方式称量出166。166=64+64+16+16+4+1+1。166=256-64-16-16+4+1+1。166=256-64-16-4-4-1-1。

HINT

Source

[Submit][Status][Discuss]

分析

讲真,这题动态规划的思路不难,上了趟WC就有了,但是废了好大劲才把这个巨型整数变成4进制,当然中间是“天马行空”就是了。

假如已经有了这个整数的四进制表示方法,如166的四进制数2212,称第1个2为第1位,第2个2为第2位,而1为第3位。

动态规划如下:

F[i][0]表示第i位上目前就是第i位数字的最小操作数。

F[i][1]表示第i位上目前是第i位数字+1的最小操作数。

G[i][0]和G[i][1]分别对应两者的方案数。

对于F数组,有如下转移——

  1. F[i][0] <- F[i - 1][0] + num[i]
  2. F[i][0] <- F[i - 1][1] + 4 - num[i]
  3. F[i][1] <- F[i - 1][0] + num[i] - 1
  4. F[i][1] <- F[i - 1][1] + 3 - num[i]

显然就是枚举达到当前转态要求的数字,可以用什么方式得到。要么是从0加到num[i],要么是从4减到num[i]。

代码

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <iostream>
  6 #include <algorithm>
  7
  8 using namespace std;
  9
 10 #define lim 100000
 11
 12 int stk[lim];
 13
 14 class BigNum
 15 {
 16 private:
 17     int s[lim];
 18
 19     char gc(void)
 20     {
 21         return getchar();
 22     }
 23
 24     void pc(char c = ‘\n‘)
 25     {
 26         putchar(c);
 27     }
 28
 29     int gl(void)
 30     {
 31         int len = lim;
 32
 33         while (!s[--len] && len);
 34
 35         len = len == 0 ? 1 : len;
 36
 37         return len;
 38     }
 39
 40 public:
 41     BigNum(void)
 42     {
 43         memset(s, 0, sizeof(s));
 44     }
 45
 46     void read(void)
 47     {
 48         int tot = 0, len = 0;
 49
 50         for (char c = gc(); c >= ‘0‘; c = gc())
 51             stk[++tot] = c - ‘0‘;
 52
 53         while (tot)s[++len] = stk[tot--];
 54     }
 55
 56     void print(void)
 57     {
 58         for (int len = gl(); len; )
 59             pc(s[len--] + ‘0‘);
 60     }
 61
 62     void println(void)
 63     {
 64         print(); pc();
 65     }
 66
 67     int mod4(void)
 68     {
 69         int res = 0;
 70
 71         for (int len = gl(); len; )
 72             res = (res*10 + s[len--]) & 3;
 73
 74         return res;
 75     }
 76
 77     void div4(void)
 78     {
 79         for (int len = gl(); len; --len)
 80             s[len - 1] += (s[len] & 3)*10, s[len] >>= 2;
 81
 82         s[0] = 0;
 83     }
 84
 85     bool not0(void)
 86     {
 87         if (gl() > 1 || s[1])
 88             return true;
 89         return false;
 90     }
 91 }num;
 92
 93 const int MOD = 1e9;
 94
 95 int f[lim][2];
 96 int g[lim][2];
 97
 98 void Min(int &a, int b)
 99 {
100     a = min(a, b);
101 }
102
103 void add(int &a, int b)
104 {
105     a += b;
106
107     if (a >= MOD)
108         a -= MOD;
109 }
110
111 signed main(void)
112 {
113     num.read();
114
115     int tot = 0;
116
117     while (num.not0())
118         stk[++tot] = num.mod4(), num.div4();
119
120     reverse(stk + 1, stk + 1 + tot);
121
122     memset(g, 0, sizeof(g));
123     memset(f, 0x3f3f3f3f, sizeof(f));
124
125     f[0][0] = 0; g[0][0] = 1;
126     f[0][1] = 1; g[0][1] = 1;
127
128     for (int i = 1; i <= tot; ++i)
129     {
130         Min(f[i][0], f[i - 1][0] + stk[i]);
131         Min(f[i][0], f[i - 1][1] + 4 - stk[i]);
132         Min(f[i][1], f[i - 1][0] + stk[i] + 1);
133         Min(f[i][1], f[i - 1][1] + 3 - stk[i]);
134     }
135
136     for (int i = 1; i <= tot; ++i)
137     {
138         if (f[i][0] == f[i - 1][0] + stk[i])
139             add(g[i][0], g[i - 1][0]);
140         if (f[i][0] == f[i - 1][1] + 4 - stk[i])
141             add(g[i][0], g[i - 1][1]);
142         if (f[i][1] == f[i - 1][0] + stk[i] + 1)
143             add(g[i][1], g[i - 1][0]);
144         if (f[i][1] == f[i - 1][1] + 3 - stk[i])
145             add(g[i][1], g[i - 1][1]);
146     }
147
148     printf("%d\n", g[tot][0]);
149 }

BZOJ_1111.cpp

@Author: YouSiki

时间: 2024-10-11 11:58:31

BZOJ 1111: [POI2007]四进制的天平Wag的相关文章

bzoj1111 [POI2007]四进制的天平Wag

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1111 [题解] 这题号注定单身. 转成四进制考虑 设f[i]表示从第i位往前的min,g[i]表示从第i位往前(第i位借1位)往前的min 那么转移随便做了.. md还要取模,没看这个wa了3发 # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm

二十四进制编码串转换为32位无符号整数(C语言实现)

typedef int BOOL; #define TRUE 1; #define FALSE 0; #define UINT_MAX 0xffffffff /* maximum unsigned int value */ enum Scale24AsciiVal { sav_aADis = 32, // 小写字母与大写字母ASCII码差值 sav_chIntDis = 48, // 字符'0'ASCII码值 }; static const char scale24[24] = {'0', '1

不同进制之间的转换

参考文章地址:http://www.cnblogs.com/o-andy-o/p/3410356.html 一. 二进制与十进制之间的转换     a.二进制转十进制(不分整数和小数从最后一位算起,每一位上的数乘以2的几次方,这个次数由这个数字所在的位置决定,从零位开始,然后相加)         01101011.001 转十进制: 第-3位   1乘2的-3次方=0.125第-2位   0乘2的-2次方=0 第-1位   0乘2的-1次方=0第0位    1乘2的0次方=1第1位    1乘

Erlang 进制转换

http://www.cnblogs.com/me-sa/archive/2012/03/20/erlang0047.html bnot unary bitwise not integer div integer division integer rem integer remainder of X/Y integer band bitwise and integer bor bitwise or integer bxor arithmetic bitwise xor integer bsl a

浅谈IP地址和子网掩码的对应关系,以及2进制和10进制详解!

大家好,我是带你们成长的凡凡- IP地址的结构:     #长度为 32 bit:先    #结构 - 网络位 + 主机位 子网掩码:      -作用           区分IP地址中的网络位与主机位          必须与IP地址,一一对应,成对出现:  -表示         纯2进制          点分十进制 (y.y.y.y) ->y的取值范围是 0 --255         /n (n表示的是子网掩码中有多少个1)      -功能实现         子网掩码中1所对应的

10进制转化成2进制,16进制

//写一个程序,将十进制,可以转换为2进制,八进制,十六进制,四进制 #include <stdio.h> #include <stdlib.h> /************************************************************************/ /* 将数字换算成2进制打印出来 */ /************************************************************************/

4进制加法-C++实现-分类讨论

思路: 1. 分四类讨论 2. 得到加和减计算方法 3. 前导0删除与符号删除 #include<iostream> #include<string> #include<iomanip> using namespace std; // 输入4进制数格式判断 bool judge(string a) { int i = 0; if(a[i] == '-' || a[i] == '+') i++; if(a[i] == '0' && a.size()-1&g

进制间的转换(二进制、八进制、十六进制、十进制)

进制转换在我们生活中使用十分频繁 我们比较常见的进制有 1.二进制 2.八进制 3.十进制 4.十六进制 5.十二进制 6.二十四进制 7...... 一.二进制 我们都知道二进制是在计算机中运用的较多,因为计算机中只有两种状态(开关或者高电平低电平) 我们一般用基数0和1来表示,二进制的运算时逢2进1 一般我们运算有两种方法 1.1-除二取余法 这个方法是一个解决方案 例如:(我们在这里是十进制转化为二进制) 13转化为二进制 13/2=6..........1 6/2=3..........

不同变量在内存中的存在形式(以16进制表示)

1 #include<stdio.h> 2 int main() 3 { 4 char a= -1; //1111 1111 1个字节 5 short b= -1; //1111 1111- 1111 1111 2个字节 6 int c= -1; //1111 1111- 1111 1111- 1111 1111- 1111 1111 4个字节 7 printf("%hhx\n",a); //打印1个字节 8 printf("%hx\n",b); //打