[bzoj3957][构造]To Add or to Multiply

55 篇文章 0 订阅
3 篇文章 0 订阅

Description

工业计算机处理器公司为顾客量身定做了非常快速、用于专门目的的处理单元。a-C-m系列的处理器(比如1-C-2和5-C-3)的指令集只有两种操作:
  • A 数值加a   • M 数值乘m
  处理器接收一个整数,执行一个A和M的指令序列(即程序)来修改输入,然后输出结果。举个例子,1-C-2处理器执行程序AAAM处理输入2返回输出10(计算过程是2→3→4→5→10),然而5-C-3处理器用相同的程序和输入返回51(2→7→12→17→51)。
  你是一个被指定做一个顶级秘密项目的a-C-m程序员。这意味着你不会被告知你的程序执行的精确输入。但会得到四个特别的值p,q,r,s,以及下列条件
  1、输入保证是一个在p、q之间的数   2、输出必须是一个在r,s之间的数。
  给你一个a-C-m处理器和p,q,r,s这四个数。你的工作是构想最短的a-C-m程序,使得任意任意x保证p≤x≤q,返回一个输出y使得r≤y≤s。如果有多个最短的程序,选择字典序最小的,而一个程序即是由A和M组成的字符串。

Input

输入包含多组数据。每组数据在一行中给你6个整数a,m,p,q,r,s,每个就像上面描述的一样。 末行输入6个0作为结束。

Output

对于每组数据,在你的程序前输出数据的编号,程序即像上面描述的一样。输出单词“empty”,如果最好的程序没有操作。输出单词“impossible”如果没有程序满足具体要求。
输出一个用空格分隔的字符串序列,任两个相邻的字符串形式分别为“nA”和“nM”,n>0。前者表示n个连续的操作A,后者表示n个连续的操作M。

Sample Input

1 2 2 3 10 20

1 3 2 3 22 33

3 2 2 3 4 5

5 3 2 3 2 3

0 0 0 0 0 0

Sample Output

Case 1: 1A 2M

Case 2: 1M 2A 1M

Case 3: impossible

Case 4: empty

HINT

所有的的a,m,p,q,r,s∈[1,1000000000],且p≤q,r≤s。

题解

感觉我已经变得奇奇妙妙了…
菜的真实
首先你可以知道,对于任意输入一个数 x x x,最终一定可以变为这样的形式
x ∗ m k + a ∗ ( t k ∗ m k + t k − 1 ∗ m k − 1 . . . + t 0 ∗ m 0 ) x*m^k+a*(t_k*m^k+t_{k-1}*m^{k-1}...+t_0*m^0) xmk+a(tkmk+tk1mk1...+t0m0)
主要是我没有把这个形式后面写成系数允许为0的形式然后就挂了
你可以发现,在 m m m不等于 1 1 1的情况下这个 k k k最多只有 30 30 30,然而 m = 1 m=1 m=1的情况下只会用加 a a a的情况,这个判掉就可以了…
所以枚举一下这个 k k k,我们只需要让 x = p x=p x=p时满足上式大于等于 r r r x = q x=q x=q时上式小于等于 s s s即可
我们可以得到他们的差分别是 s 1 s1 s1 s 2 s2 s2,不妨设后面的式子为 p 1 p1 p1 p 2 p2 p2
我们发现 p 1 , p 2 p1,p2 p1,p2均是由 a a a组成的,所以可以把 s 1 = ⌈ s 1 a ⌉ s1=\lceil\frac{s1}{a}\rceil s1=as1 s 2 = ⌊ s 2 a ⌋ s2=\lfloor\frac{s2}{a}\rfloor s2=as2,然后构造后面的多项式
发现其实这是一个 m m m进制的数,我们把 s 1 , s 2 s1,s2 s1,s2写成 m m m进制,类似数位dp一下就可以了…
大概就是如果前面不顶两个界,直接填0就可以了
如果顶着下界,看看这个位能不能填一个大于下界的数,让后面的位置全部填0
否则的话按下界填就可以了
OZY天下第一!!!!!!!!!!!

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
int a,m,p,q,r,s;
int sum;
int temp[2][35],ln[2],ans[35],lin[35];
void get(int x,int len,int opt)
{
	memset(temp[opt],0,sizeof(temp[opt]));
	LL base=1;ln[opt]=0;
	for(int i=1;i<=len;i++)
	{
		temp[opt][++ln[opt]]=x%m;
		if(i==len)temp[opt][i]=x;
		x/=m;
		if(!x)return ;
	}
}

int num1[110],num2[110],ln1;
int as1[110],as2[110],ln2;
void work(int mx)
{
	ln1=0;memset(num1,0,sizeof(num1));
	for(int i=1;i<=mx;i++)
	{
		if(lin[i])
		{
			num1[++ln1]=lin[i];num2[ln1]=1;
		//	if(i!=mx)
			ln1++;
		}
		if(!ln1)ln1=1;
		if(i!=mx)num1[ln1]++,num2[ln1]=2;
	}
	if(lin[mx])ln1--;
}
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	int tt=0;
	while(++tt)
	{
		memset(num2,0,sizeof(num2));
		memset(as1,0,sizeof(as1));memset(as2,0,sizeof(as2));
		a=read();m=read();p=read();q=read();r=read();s=read();
		if(!a&&!m&&!p&&!q&&!r&&!s)break;
		printf("Case %d: ",tt);
		if(p>=r&&q<=s)puts("empty");
		else if(q>s)puts("impossible");
		else
		{
			if(m==1)
			{
				int down=(r-p)/a;if((r-p)%a)down++;
				int up=(s-q)/a;if((s-q)%a)up++;
				if(p+1LL*down*a>s||q+1LL*up*a>s||down>up)puts("impossible");
				else printf("%dA\n",down);
			}
			else
			{
				bool tf=false;sum=(1<<31-1);
				LL base=1;int del=a;a=1;
				for(int i=0;i<=30;i++)
				{
					memset(lin,0,sizeof(lin));
					if(i)base=base*m;
					if(base>s||1LL*p*base>s||1LL*q*base>s)break;
					int s1=r-p*base,s2=s-q*base;
					if(s1<0)s1=0;
					s1=(s1+del-1)/del;s2=s2/del;
					get(s1,i+1,0);get(s2,i+1,1);
					int tot=i,gg=0;bool yes=0,ok=1;
					for(int j=max(ln[0],ln[1]);j>=1;j--)
					{
						if(!gg)//前面填的都是顶下界的 
						{
							if(a*((temp[0][j]+a-1)/a)>temp[1][j]){ok=0;break;}
							int num=a*((temp[0][j]+a-1)/a);
							if(num>temp[0][j])tot+=num/a,lin[j]=num/a,gg=1;
							else
							{
								if(num+a<=temp[1][j]||yes)
								{
									bool bk=false;
									for(int k=j-1;k>=1;k--)if(temp[0][k]){bk=true;break;}
									if(bk)tot+=num/a+1,lin[j]=num/a+1,gg=1;
									else tot+=num/a,lin[j]=num/a;
								}
								else tot+=num/a,lin[j]=num/a;
							}
						}
						else lin[j]=0;
						if(temp[0][j]<temp[1][j])yes=1;
					}
					if(!ok)continue;
					tf=1;work(i+1);
					if(tot<sum)
					{
						sum=tot;
						memcpy(as1,num1,sizeof(as1));memcpy(as2,num2,sizeof(as2));
						ln2=ln1;
					}
					else if(tot==sum)
					{
						bool ok=true;
						for(int i=ln1,j=ln2;i>=1,j>=1;i--,j--)
						{
							if(num2[i]>as2[j]){ok=false;break;}
							if(num2[i]<as2[j])break;
							if(num1[i]==as1[j])continue;
							else
							{
								if(num1[i]>as1[j])
								{
									if(num2[i]>as2[j-1]){ok=false;break;}
									else break;
								}
								else
								{
									if(as2[j]>num2[i-1]){ok=false;break;}
									else break;
								}
							}
						}
						if(ok)
						{	
							memcpy(as1,num1,sizeof(as1));memcpy(as2,num2,sizeof(as2));
							ln2=ln1;
						}
					}
				}
				if(!tf)puts("impossible");
				else
				{
					for(int i=ln2;i>=1;i--)
					{
						printf("%d",as1[i]);
						if(as2[i]==1)putchar('A');
						else putchar('M');
						if(i!=1)putchar(' ');
					}
					puts("");
				}
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值