首先我们观察加操作和乘操作会对区间产生那些影响。加操作只会平移区间,而乘操作既能移动区间还能放大区间。因此我们不难想到,如果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的更多相关文章

  1. leetcode@ [2/43] Add Two Numbers / Multiply Strings(大整数运算)

    https://leetcode.com/problems/multiply-strings/ Given two numbers represented as strings, return mul ...

  2. [LeetCode] 415 Add Strings && 67 Add Binary && 43 Multiply Strings

    这些题目是高精度加法和高精度乘法相关的,复习了一下就做了,没想到难住自己的是C++里面string的用法. 原题地址: 415 Add Strings:https://leetcode.com/pro ...

  3. UVa 10954,Add All

    Huffman编码简化版,优先队列搞定. 1A 调试的时候发现一个问题..木有想明白...问题代码里给出,哪位大神给解释下. #include <iostream> #include &l ...

  4. 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 枚 ...

  5. 【uva 10954】Add All(算法效率--Huffman编码+优先队列)

    题意:有N个数,每次选2个数合并为1个数,操作的开销就是这个新的数.直到只剩下1个数,问最小总开销. 解法:合并的操作可以转化为二叉树上的操作[建模],每次选两棵根树合并成一棵新树,新树的根权值等于两 ...

  6. UVa 11375 - Matches

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  7. [LeetCode] Add Strings 字符串相加

    Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...

  8. [LeetCode] 415. Add Strings 字符串相加

    Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...

  9. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. KVC笔记

    利用KVC可以随意修改一个对象的属性或者成员变量(并且私有的也可以修改) 示例代码:  示例一: Person *p = [[Person alloc] init]; p.dog = [[Dog al ...

  2. 转 父表字表统计查询的sql练习

    create table father(        f_id number(2) primary key,        f_name varchar2(10) ); create table s ...

  3. [转]Java中的回车换行符/n /r /t

    '\r'是回车,'\n'是换行,前者使光标到行首,后者使光标下移一格.通常用的Enter是两个加起来.下面转一篇文章. 回车和换行 今天,我总算搞清楚"回车"(carriage r ...

  4. C#函数式编程之部分应用

    何谓函数式编程 相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类.而函数式编程则更加细化,致使我们解决一个功能的基本单元是函数,而不是类,每个功能都是由多个 ...

  5. Lambda应用设计模式

    前言 在使用 Lambda 表达式时,我们常会碰到一些典型的应用场景,而从常用场景中抽取出来的应用方式可以描述为应用模式.这些模式可能不全是新的模式,有的参考自 JavaScript 的设计模式,但至 ...

  6. 困扰多日的C#调用Haskell问题竟然是Windows的一个坑

    最近一直被C#调用Haskell时的“尝试读取或写入受保护的内存”问题所困扰(详见C#调用haskell遭遇Attempted to read or write protected memory,C# ...

  7. [转]Sublime Text 2 设置文件详解

    Sublime Text 2是那种让人会一眼就爱上的编辑器,不仅GUI让人眼前一亮,功能更是没的说,拓展性目前来说也完全够用了,网上介绍软件的文章和推荐插件的文章也不少,而且很不错,大家可以去找找自己 ...

  8. [ACM_暴力][ACM_几何] ZOJ 1426 Counting Rectangles (水平竖直线段组成的矩形个数,暴力)

    Description We are given a figure consisting of only horizontal and vertical line segments. Our goal ...

  9. Qt 5.3.1 版本应用程序的发布问题

    问题描述:用过Qt的朋友,都知道,完成的Qt程序,只能在QT环境里运行.在debug环境里,没有配置环境路线的情况下,必须包含多个dll库,然而每个dll库的大小确实很大的.但有时候还是会失败的,在一 ...

  10. jquery的height()和javascript的height总结,js获取屏幕高度

    jquery的height()和javascript的height总结,js获取屏幕高度 2014年9月18日 15048次浏览 引子 今天是九一八事变八十三周年,大家勿忘国耻!加油学习!经济和技术等 ...