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 ...
随机推荐
- Monte Carlo 数值积分
var amount = 0.0d; var hitTheTargetCount = 0.0d; var M = 2.0d; var rnd=new Random(); ; i < ; i++) ...
- Memcached监听多个端口_同一台Windows机器中启动多个Memcached服务
下载Memcached服务器 假设你解压在"C:\Program Files\memcached\memcached.exe" 那么可以如下创建多个服务监听不同的端口啦 监听第一个 ...
- java线程详解(二)
1,线程安全 先看上一节程序,我们稍微改动一下: //线程安全演示 //火车站有16张票,需要从四个窗口卖出,如果按照上面的多线程实现,程序如下 class Ticket implements Run ...
- 基于注解的DWR使用
dwr3.0支持使用注解,如果不喜欢配置dwr.xml文件,注解是个不错的方法,简单快捷. 步骤如下: 1.配置web.xml文件,需要在DwrServlet里加classes初始化参数: <i ...
- python 传值引用和传参引用
调用同事的函数,传入goods_list,获取商品信息,然后将商品信息与goods_list的信息进行匹配,合并. 但是同事返回数据的同时改变了我传入的参数,goods_list.相当于传参引用,也就 ...
- IOS笔记之UIKit_UIAlertView、UIActionSheet
//首先必须继承协议 @interface TRViewController : UIViewController<UIAlertViewDelegate,UIActionSheetDelega ...
- 解决VS2013+IE11调试DevExpress ASP.NET MVC的性能问题
将一个MVC项目从12.2升级到14.2,VS2012升到2013,发现使用IE11调试非常慢卡死,CPU占用100%,后来经过排除,发现只有DevExpress的MVC项目有这个问题. 最后在Dev ...
- Dynamic CRM 2013学习笔记(十三)附件上传 / 上传附件
上传附件可能是CRM里比较常用的一个需求了,本文将介绍如何在CRM里实现附件的上传.显示及下载.包括以下几个步骤: 附件上传的web页面 附件显示及下载的附件实体 调用上传web页面的JS文件 实体上 ...
- 第十四章:样式(Style)和主题(Theme)
简介 Android的样式(Style)和主题(Theme)文件就好比WEB开发中的CSS一样,可以实现UI界面的风格统一管理,这和Windows平台的XAML格式(Silverlight.WPF)类 ...
- Book Review: PowerShell 3.0 Advanced Administration Handbook
Recently I read a book, PowerShell 3.0 Advanced Administration Handbook, which I found really worthy ...