数学+模拟

细节很多

首先我们发现,如果两个区间已经包含,那么可以输出empty,一个数能通过变换得到另一个区间的数,这个区间的大小必须小于等于终点区间的大小。加法不会改变区间大小,只有乘法会改变,而且每次乘法会使区间大小扩大m倍。其实我们发现,最终一个数会变成p*x+y,x是m的几次幂,y是一个a乘上一些m的幂再加上一些a.x=m^l+a(A0*m^l+A1*m^n-1+...+An)所以我们就是要把后面的东西展开。

但是题目要求操作数最少且字典序最小。所以我们要枚举最大的次数,枚举次数时还要保证次数最少。保证次数最少应该更多用乘法保证,所以就是把一些加法换成乘法,也应该尽量用高次代替低次,所以我们每次枚举次数,然后枚举每位,把每位用尽量大的数替代,后面的数清零,然后判断。字典序的判断比较鬼畜。

当m=0或m=1时把m赋成极大值,这样就可以保证m不会乘,impossible就是先把ans变成一个极大值,然后判断。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, char> PII;
vector<PII> ans;
ll a, m, p, q, r, s;
int kase;
bool cp(vector<PII> &A, vector<PII> &B)
{
ll s1 = , s2 = ;
for(int i = ; i < A.size(); ++i)
s1 += A[i].first;
for(int i = ; i < B.size(); ++i)
s2 += B[i].first;
// printf("%d %d\n", A.size(), B.size());
if(s1 != s2)
return s1 < s2;
int lim = min(A.size(), B.size());
for(int i = ; i < lim; ++i)
{
if(A[i].second != B[i].second)
return A[i].second < B[i].second;
if(A[i].first != B[i].first)
{
if(A[i].second == 'A')
return A[i].first > B[i].first;
else
return A[i].first < B[i].first;
}
}
return A.size() < B.size();
}
void update(int x, ll target)
{
// printf("x=%d target=%d\n", x, target);
vector<PII> v; v.clear();
for(int i = ; i < x; ++i)
{
if(target % m)
v.push_back(make_pair(target % m, 'A'));
target /= m;
if(v.empty() || v.back().second == 'A')
v.push_back(make_pair(1ll, 'M'));
else
++v.back().first;
}
if(target)
v.push_back(make_pair(target, 'A'));
reverse(v.begin(), v.end());
// for(int i = 0; i < v.size(); ++i)
// printf(" %d%c", v[i].first, v[i].second);
// printf("\n");
if(cp(v, ans))
swap(ans, v);
}
void process(int low, int high, int m, int t)
{
for(int i = , j = ; i <= t; ++i, j *= m)
{
int x = (low + j - ) / j * j;
if(x > high)
break;
update(t, x);
}
}
int main()
{
// freopen("output.txt", "w", stdout);
while(scanf("%lld%lld%lld%lld%lld%lld", &a, &m, &p, &q, &r, &s))
{
if(!a && !m && !p && !q && !s && !r)
break;
ans.clear();
if(m == || m == )
m = 1000000010ll;
printf("Case %d:", ++kase);
if(p >= r && q <= s)
{
printf(" empty\n");
continue;
}
ans.push_back(make_pair(2000000000ll, 'A'));
for(int mul = ; q <= s && q - p <= s - r; ++mul, p *= m, q *= m)
{
ll minadd = max(0ll, (r - p + a - ) / a), maxadd = (s - q) / a;
if(minadd > maxadd)
continue;
process(minadd, maxadd, m, mul); //mul:最多乘mul次
}
if(ans[].first == 2000000000ll)
{
printf(" impossible\n");
continue;
}
for(int i = ; i < ans.size(); ++i)
printf(" %lld%c", ans[i].first, ans[i].second);
printf("\n");
}
// fclose(stdout);
return ;
}

bzoj3957的更多相关文章

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

随机推荐

  1. 【译】x86程序员手册17-第6章保护

    Chapter 6 Protection 第六章 保护 6.1 Why Protection? 为什么要保护? The purpose of the protection features of th ...

  2. [源码阅读]RocketMQ-策略篇

    一:为什么要阅读rocketmq的源码? 1 可以了解mq的底层实现逻辑. 二:打算怎么读,行动路径是哪儿些? 1: 本地启动 2 分步调试 3  fork项目,添加中文注释,提交到自己的代码库.并改 ...

  3. Redis 之order set有序集合结构及命令详解

    1.zadd key score1 value1 score2 value2  添加元素 2.zrem key value1 value2 ..  删除集合中的元素 3.zremrangebyscor ...

  4. Python 索引切片

    #负数开头,只有比负数大才有数据 num = [1,2,3,4,5,6,7,8,9,10] print(num[-5:5]) num = [1,2,3,4,5,6,7,8,9,10] print(nu ...

  5. exgcd扩展欧几里得求解的个数

    知识储备 扩展欧几里得定理 欧几里得定理 (未掌握的话请移步[扩展欧几里得]) 正题 设存在ax+by=gcd(a,b),求x,y.我们已经知道了用扩欧求解的方法是递归,终止条件是x==1,y==0: ...

  6. 洛谷P1055 ISBN号码【字符数组处理】

    题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括 99 位数字. 11 位识别码和 33 位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号 ...

  7. [HDU1403]Longest Common Substring(后缀数组)

    传送门 求两个串的公共子串(注意,这个公共子串是连续的一段) 把两个串连在一起,中间再加上一个原字符串中不存在的字符,避免过度匹配. 求一遍height,再从height中找满足条件的最大值即可. 为 ...

  8. CF410div2 A. Mike and palindrome

    /* CF410div2 A. Mike and palindrome http://codeforces.com/contest/798/problem/A 水题 */ #include <c ...

  9. poj 2031

    #include<stdio.h> #include<math.h> #include<stdlib.h> #define N 200 double co(doub ...

  10. 递归算法详细分析->C

    C通过运行时堆栈支持递归函数的实现.递归函数就是直接或间接调用自身的函数.     许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的<C语言程序设计> ...