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

2023-11-25 16:40
文章标签 bzoj poi2007 进制 天平 1111 wag

本文主要是介绍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

转载于:https://www.cnblogs.com/yousiki/p/6091707.html

这篇关于BZOJ 1111: [POI2007]四进制的天平Wag的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/424160

相关文章

usaco 1.2 Palindromic Squares(进制转化)

考察进制转化 注意一些细节就可以了 直接上代码: /*ID: who jayLANG: C++TASK: palsquare*/#include<stdio.h>int x[20],xlen,y[20],ylen,B;void change(int n){int m;m=n;xlen=0;while(m){x[++xlen]=m%B;m/=B;}m=n*n;ylen=0;whi

uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401

题意是求在base进制下的 n!的结果有几位数,末尾有几个0。 想起刚开始的时候做的一道10进制下的n阶乘末尾有几个零,以及之前有做过的一道n阶乘的位数。 当时都是在10进制下的。 10进制下的做法是: 1. n阶位数:直接 lg(n!)就是得数的位数。 2. n阶末尾0的个数:由于2 * 5 将会在得数中以0的形式存在,所以计算2或者计算5,由于因子中出现5必然出现2,所以直接一

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客  这节就是真正的存储数据了   理清一下思路: 1.存储路径并检查 //2进制文件类存储private static string Data_Binary_Pa

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(2) (*****生成数据结构类的方式特别有趣****)-CSDN博客 做完了数据结构类,该做一个存储类了,也就是生成一个字典类(只是声明)  实现和上一节的数据结构类的方式大同小异,所

itoa()函数,10进制转换到(2~36)进制

先看下itoa()的函数说明吧: 功 能:把一整数转换为字符串   用 法:char *itoa(int value, char *string, int radix);    详细解释:itoa是英文integer to array(将int整型数转化为一个字符串,并将值保存在数组string中)的缩写.    参数:  value: 待转化的整数。            radix:

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(2) (*****生成数据结构类的方式特别有趣****)

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(1)-CSDN博客 本节内容 实现目标 通过已经得到的Excel表格数据,生成对应类对象(不赋值),一张表就是一个对象,其中包含了如下的字段  就像这样子  实现思路 上

[C/C++入门][进制原理]31、求分数序列和

题目来自于信息学奥赛 1078 分析: 这道题看起来比较复杂,实际上只需要通过两个公式,一次性求出分母和分子,然后把这个求出来的数加入到变量和中。甚至都不需要知道总共游哪些数。数组都用不上。循环就能解决。 #include <iostream>#include <iomanip> // 用于格式化输出using namespace std;int main() {double s

Java生成随机数工具类,进制之间的转换工具类,获取指定时间,时间格式转换工具类

废话不多说,贡献一下code 1.编号生成工具 import org.apache.commons.lang3.StringUtils;import java.math.BigInteger;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;/*** 编号生成工具*/@

2.第二阶段x86游戏实战2-认识进制、理解数据宽度和位的概念

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 工具下载: 链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3 提取码:6tw3 复制这段内容后打开百度网盘手机App,操作更方便哦 上一个内容:1.第二阶段x86游戏实战2-前言 进制、数据宽度、位是一

进制的功效

昨晚做梦时忽然一道灵光直击天灵盖,眼前冒出一行字:十进制,二进制、八进制、十六进制,为嘛都是“进制”?就不能是二出头、八回首、十全大补丸吗? 答曰:进制,就是进位制。 有了“进位”这款利器,就可以实现一个神奇的功能:以有限应无限。就是说可以用有限的数字符号来表示所有的数值,比如二进制,只需要两个数字就能表示出无穷多的数,甚至是万事万物。 进位的“位”指的是位置,同一个数字放在不同的位置有不同