首先我们观察加操作和乘操作会对区间产生那些影响。加操作只会平移区间,而乘操作既能移动区间还能放大区间。因此我们不难想到,如果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. Mysql --分区表(2)

    分区类型 RANGE分区 range分区的表是利用取值范围将数据分成分区,区间要连续并且不能互相重叠,使用values less than操作符进行分区定义 LIST分区 LIST分区是建立离散的值列 ...

  2. opengles tutorial

    https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide ...

  3. Robot Framework-Windows版本安装

    Robot Framework-Mac版本安装 Robot Framework-Windows版本安装 Robot Framework-工具简介及入门使用 Robot Framework-Databa ...

  4. nginx安装启动

    参考:http://network.51cto.com/art/201005/198198_4.htm 下载nginx tar.gz安装包下载pcre tar.gz安装包 安装pcretar zxvf ...

  5. Maven 跳过测试命令行参数 skip test

    mvn    package -Dmaven.test.skip=true

  6. Linux下which、whereis、locate、find命令的区别

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索.这些是从网上找到的资料(参考资料1),因为有时很长时间不会用到,当要用的时候经常弄混了,所以放到这里方便使用. w ...

  7. Android 5.x特性概览三

    上节,对Material Design样式做了介绍,这节我们介绍Palette. 在Android发展的长河中,UI越来越成为Google的发展重心.上文提到Android 5.x 使用palette ...

  8. Css3图标库

    最近在研究icon font图标字库,觉得很有意思,于是找了一些比较好的在线字库.大都是开源的,而且各有特色,推荐给大家! 阿里icon font字库 http://www.iconfont.cn/ ...

  9. Salesforce 生成测试可用 Id

    在写 Test Class 的时候,有时候需要一批有 Id 的数据或者把 Id 作为参数等情况,在数据关系比较复杂的情况下去造真实数据有些麻烦,于是找到这样一个可以生成 Id 的方法可以用来辅助测试! ...

  10. servlet--转向forward与重定向

    当使用forward形式跳转servlet时,地址栏会显示跳转前的servlet访问地址. 跳转是在服务端实现的,客户浏览器并不知道该跳转动作. forward可以跳转到另一个servlet,jsp, ...