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 ...
随机推荐
- JS 插件使用
1.时间控件的使用 My97DatePicker WdatePicker({ minDate: '%y-%M-{%d}'}) 默认当前日期以后 LoanMessage.LoanAppAgentMode ...
- 斯坦福第十三课:聚类(Clustering)
13.1 无监督学习:简介 13.2 K-均值算法 13.3 优化目标 13.4 随机初始化 13.5 选择聚类数 13.1 无监督学习:简介 在这个视频中,我将开始介绍聚类算法.这将是一个 ...
- C++字符串常量
C++字符串常量 当一个字符串常量出现于表达式中时,它的值是个指针常量.编译器把这个指定字符的一份copy存储在内存的某个位置(全局区),并存储一个指向第一个字符的指针. #include <i ...
- dubbo demo实现
粗略的写了一个dubbo的demo,使用了alibaba的dubbo,还有zookeeper来做配置中心 参考资料地址: http://dubbo.io/User+Guide-zh.htm#UserG ...
- HibernateTemplate和HibernateDaoSupport(spring注入问题)
HibernateTemplate HibernateTemplate是spring提供的一个就hibernate访问持久层技术而言.支持Dao组件的一个工具.HibernateTemplate提供持 ...
- weblogic10.3.6 自动启动服务后停止的解决方案
windows部署weblogic后,需要手动开启weblogic管理员服务器,即Start Admin Server for Weblogic Server Domain,不过这样的话每次重启或者不 ...
- Linux中强制结束一个进程的终极方法
在 Linux Ubuntu 服务器上用 dnx 基于 Kestrel 成功运行一个 ASP.NET 5 站点后,怎么也无无法退出. 运行的命令如下: /data/git/dnx/artifacts/ ...
- Linux上成功编译CoreCLR源代码
>>Build日期:2015-2-5下午(编译失败). 开始Linux发行版用的是CentOS 6.5,操作步骤: 1)配置git: git config --global http.ss ...
- [MSSQL2005]再看CTE
个人认为CTE最大的做点是可以处理树状存储的数据了 例如类似这样设计的数据表,ID,ParentID这样的设计使用CTE就非常方便,原因就是CTE可以自引用,达到类似递归的效果 那么问题来了,如何使用 ...
- ASP.NET中GridView控件删除数据的两种方法
今天在用GridView控件时,发现了一个问题,就是使用GridView控件在删除数据时的问题.接下来我们通过模板列方式和CommandField方式删除某条数据讲解下两者之间的区别. 方式一:通 ...