UVA 1101 To Add or to Multiply
首先我们观察加操作和乘操作会对区间产生那些影响。加操作只会平移区间,而乘操作既能移动区间还能放大区间。因此我们不难想到,如果m>1的话乘操作是log级别的,一方面是因为区间的大小不能超过s-r,另一方面区间的最大值不能超过r,这两方面都能决定乘操作的个数是log级别的,因此一种可行的思路就是枚举乘操作的次数,然后再看怎么安排加操作。
同时我们还能发现,这些操作不会改变区间内数的顺序,因此只要最小值和最大值都在s到r之间就可以,并且如果我们固定了乘操作的次数,相当于固定了最终区间的宽度,这样根据最小值就能推出最大值,因此我们可以只约束最小值在某个范围内,就能使得最小值和最大值都在s到r之间,这样我们又进一步简化了问题。
现在的问题就是在乘操作固定的情况下,要怎么安排加操作才能使最小值(也就是p)落在这个范围(指前面所说的“我们可以只约束最小值在某个范围内”的这个范围)内。
我们会发现不论加操作和乘操作的顺序如何,最后p变成的数都能表示成x*p+y的形式,而且x是m的整数次幂,y是m的一些整数次幂和a的乘积,而且如果把y中的那个公因子的a提出来,就会发现剩下的部分就是m的一些整数次幂的和,而且这些整数次幂的系数之和就是加法的次数。
用数学一点的形式表示上面加粗的部分就是说y=x0 * m^0 + x1* m^1 + x2 * m^2 + ...,其中x0 + x1 + x2 ...得到的值就是加法的次数,并且x0这个部分表示的是最后才加的那些a,x1这个部分表示的是在进行最后一次乘m的操作前最后加的那些a,x2这个部分表示……
接下来我们可以先求一个不小于r的一个最小的x*p+y,因为x已经知道了,是m的某次幂,在乘操作次数固定后就是定值了,而且y一定是a的整数倍,那么结合模运算就不难求得y的值了,这样就得到了不小于r的一个最小的x*p+y,如果这个值都不在前面所说的那个范围的话,那么这种乘操作次数下就一定无解了。
那么如果这个值在所说的那个范围内呢?那么一定会有一个可行解。还会不会有其他可行解呢?是有可能的,因为毕竟我们只求了一个最小的x*p+y,但什么情况下才有可能更新最优解呢?至少也得比我们刚刚算的这个可行解更优吧,但是乘法次数一定固定了呀,那么我们就考虑让加法次数更少一些。而我们刚刚说了y=x0 * m^0 + x1* m^1 + x2 * m^2 + ...,这个实际上不就是一个m进制数么,如果想让各个位上的数字之和更小的话就必须要产生进位,这样才可能消掉一部分,但却只付出增加一个进位的代价,这个进位要么只使各位数字之和增加1,要么还能进一步减少各位数字之和的值。所以我们就可以从低位到高位依次考虑可不可以进位了,那么就先考虑能不能通过增加m-x0消掉x0,如果可以的话我们再考虑能不能在原有的基础上再增加(m-x1)*m从而消掉x1,如果可以的话再考虑……就这样一直消到不能消为止,期间每消一次就更新一次最优解。
前面在讨论什么情况下有可能更新最优解的时候其实少了一点没有考虑,就是操作数是一样的,但是可能字典序会更小。不过这点其实是不用考虑的,因为如果存在这种情况,那么一定是先产生进位之后才能再出现这样的情况,而刚产生进位的时候就要么是操作数一样,要么是操作数更小了,所以就不用再考虑这种情况了,只需要考虑刚进位的时候就行了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define MAXN 110
typedef long long LL;
int A, M, P, Q, R, S;
struct List
{
int s, n, cnt[MAXN];
bool add[MAXN];
bool operator < (const List &t) const
{
if(s != t.s) return s < t.s;
int p = , r = cnt[], tp = , tr = t.cnt[];
while(p < n && tp < t.n)
{
if(add[p] && !t.add[tp]) return true;
if(!add[p] && t.add[tp]) return false;
int min = std::min(r, tr);
r -= min, tr -= min;
if(r == ) r = cnt[++ p];
if(tr == ) tr = t.cnt[++ tp];
}
return p == n && tp < t.n;
}
}ans;
List gen(int a[], int mn)
{
List ret;
ret.s = mn, ret.n = ;
for(int i = , &n = ret.n; i <= mn; i ++)
{
ret.s += a[i];
if(a[i] > )
{
ret.cnt[n] = a[i], ret.add[n] = true;
++ n;
}
if(i < mn)
{
if(n == || ret.add[n - ])
{
ret.cnt[n] = , ret.add[n] = false;
++ n;
}
else ++ ret.cnt[n - ];
}
}
return ret;
}
void process(int mn, int p, int px, int py)
{
if(p > px) px = p;
LL sum = ((p - px) % A + A) % A + px;
if(sum > py) return;
sum = (sum - p) / A;
int t = sum, max = (py - p) / A, a[MAXN];
for(int i = mn; i > ; i --) a[i] = t % M, t /= M;
a[] = t; List opt;
for(int i = mn, fac = ; i >= ; i --, fac *= M)
{
opt = gen(a, mn);
if(opt < ans) ans = opt;
if(i > && a[i] != )
{
sum += (LL)(M - a[i]) * fac, a[i] = M;
if(sum > max) break;
for(int j = i; j > && a[j] == M; j --)
++ a[j - ], a[j] = ;
}
}
}
int main()
{
int t = ;
while(scanf("%d%d%d%d%d%d", &A, &M, &P, &Q, &R, &S), A > )
{
ans.s = INF;
LL len = Q - P, p = P;
for(int i = ; p <= S - len && len <= S - R; i ++, len *= M, p *= M)
{
process(i, p, R, S - len);
if(M == ) break;
}
printf("Case %d:", ++ t);
if(ans.s == INF) printf(" impossible");
else if(ans.s == ) printf(" empty");
else
{
for(int i = ; i < ans.n; i ++)
printf(" %d%c", ans.cnt[i], ans.add[i] ? 'A' : 'M');
}
printf("\n");
}
return ;
}
UVA 1101 To Add or to Multiply的更多相关文章
- leetcode@ [2/43] Add Two Numbers / Multiply Strings(大整数运算)
https://leetcode.com/problems/multiply-strings/ Given two numbers represented as strings, return mul ...
- [LeetCode] 415 Add Strings && 67 Add Binary && 43 Multiply Strings
这些题目是高精度加法和高精度乘法相关的,复习了一下就做了,没想到难住自己的是C++里面string的用法. 原题地址: 415 Add Strings:https://leetcode.com/pro ...
- UVa 10954,Add All
Huffman编码简化版,优先队列搞定. 1A 调试的时候发现一个问题..木有想明白...问题代码里给出,哪位大神给解释下. #include <iostream> #include &l ...
- bzoj3957: [WF2011]To Add or to Multiply
gay队牛逼! 我们可以强行拆一下柿子,最终得到的值会是m^k*x+m^k*u(k)*a+m^k-1*u(k-1)*a……m^0*u(0)*a 其中u表示后面有i个m的a有多少个 答案就是k+∑u 枚 ...
- 【uva 10954】Add All(算法效率--Huffman编码+优先队列)
题意:有N个数,每次选2个数合并为1个数,操作的开销就是这个新的数.直到只剩下1个数,问最小总开销. 解法:合并的操作可以转化为二叉树上的操作[建模],每次选两棵根树合并成一棵新树,新树的根权值等于两 ...
- UVa 11375 - Matches
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...
- [LeetCode] Add Strings 字符串相加
Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...
- [LeetCode] 415. Add Strings 字符串相加
Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
随机推荐
- easyUI学习1
panel组件: <div id="p" class="easyui-panel" title="My Panel" style=&q ...
- ubuntu下phpmyadmin配置
经常出现的问题就是明明安装了phpmyadmin但却在输入 http://localhost/phpmyadmin的时候,没有出现管理界面,反而出现没有找到的页面. 不急,我们先安装再了phpmyad ...
- Robots on a grid(DP+bfs())
链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=25585 Current Server Time: 2013-08-27 20:42:26 Ro ...
- JAVA的JNI调用
由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分. 一般步骤: 先是写普通的Java类,其中包括本地方法调用. 然后编译这个Java类,调 ...
- LINUX RHEL AS 4 + ORACLE10G安装详解
第一部分:LINUX RHEL AS 4 安装 运行提示: 1)按键盘的前后键可以调节光标所在的位置 2)在选项前面的括号中打上*号或者去掉*号,选中这条选项用空格键操作 3)在vi编辑文件时,键盘按 ...
- spring jpa @Query中使用in
@Modifying @Query("delete from SmTenant s where s.id in ?1") void deleteByIds(List<Long ...
- 基于python的堡垒机
一 堡垒机的架构 堡垒机的核心架构通常如下图所示: 二.堡垒机的一般执行流程 管理员为用户在服务器上创建账号(将公钥放置服务器,或者使用用户名密码) 用户登陆堡垒机,输入堡垒机用户名密码,显示当前用户 ...
- xps 文件操作笔记
1. 在 Silverlight 显示XPS文件,参考:http://azharthegreat.codeplex.com/ 2. Word,Excel, PPT 文件转换为XPS: 参考一(老外写的 ...
- 学习WPF——WPF布局——初识布局容器
StackPanel堆叠布局 StackPanel是简单布局方式之一,可以很方便的进行纵向布局和横向布局 StackPanel默认是纵向布局的 <Window x:Class="Wpf ...
- Hibernate关联映射(转载)
原文:http://www.cnblogs.com/huxi/archive/2009/12/15/1624988.html 以简单的两个类为例: User(int id, String name) ...