题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1104
Remainder
Time Limit: 6000/3000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5042 Accepted Submission(s): 1297。
Problem Description
Coco is a clever boy, who is good at mathematics. However, he is puzzled by a difficult mathematics problem. The problem is: Given three integers N, K and M, N may adds (‘+’) M, subtract (‘-‘) M, multiples (‘*’) M or modulus (‘%’) M (The definition of ‘%’ is given below), and the result will be restored in N. Continue the process above, can you make a situation that “[(the initial value of N) + 1] % K” is equal to “(the current value of N) % K”? If you can, find the minimum steps and what you should do in each step. Please help poor Coco to solve this problem.
You should know that if a = b * q + r (q > 0 and 0 <= r < q), then we have a % q = r.
Input
There are multiple cases. Each case contains three integers N, K and M (-1000 <= N <= 1000, 1 < K <= 1000, 0 < M <= 1000) in a single line.
The input is terminated with three 0s. This test case is not to be processed.
Output
For each case, if there is no solution, just print 0. Otherwise, on the first line of the output print the minimum number of steps to make “[(the initial value of N) + 1] % K” is equal to “(the final value of N) % K”. The second line print the operations to do in each step, which consist of ‘+’, ‘-‘, ‘’ and ‘%’. If there are more than one solution, print the minimum one. (Here we define ‘+’ < ‘-‘ < ‘’ < ‘%’. And if A = a1a2…ak and B = b1b2…bk are both solutions, we say A < B, if and only if there exists a P such that for i = 1, …, P-1, ai = bi, and for i = P, ai < bi)
Sample Input
2 2 2
-1 12 10
0 0 0
Sample Outputt
0
2
*+
——————————————————————————————————
题意:
输入n, k, m,问经过几次操作后的n%k=(初始的n+1)%k
四个操作 : +m, -m, *m, %m(注意这个)
仔细读题, 题中说的是在数学上的取余(mod), 而在计算机上的取余是区别于数学上的。(区别在于mod的结果均为正,而%的结果可正可负,取决于左操作数)
eg :mod a = (b % a + a) % a 括号里的目的是把左操作数转成正数
理解了这些这题就很简单了,简单广搜即可。
如还不太理解(像我AC之前一样)建议学习下同余定理…
参考其他博主 : https://blog.csdn.net/weixin_30325971/article/details/96501119
摘自HDOJ:
%只能出现在第一个位置或者出现在的后面,且%最多只能出现两次。
因为对任意n,( n pe m ) % m = n % m. 对于乘法则是不一定的,n * m % m 必为0。
由于一系列{+,-,%}运算相当于在n的基础上,‘+’相当于加上若干个m,‘-’相当于减去若干
个m,‘%’相当于一次同时减去(或者加上)若干个m。而他们的总和带来的结果就是n的变化是
m的整数倍,所以上面的式子相等。也就是说如果有一个序列中有‘%’,则它的前面要么是空的,
要么是‘’,因为如果是其他的只会使得操作序列更长。例如:
±±+++%+±-可以变成%+±-,后者比前者更短。
%±±-+%+这样的路径也是不存在的,因为%使得n为0,而后面的%也为0,
重复,所以不会入队列的。
因为‘%’出现的情况很有限,并且出现的位置,也可以知道。特殊处理一下,就可以了。其他的对k取余没有问题。
代码解读:
一方面因为为了不产生溢出进行了 %(km) 操作
另一方面因为存在%m的操作,所以在防止溢出时不能直接 % m % k,可能产生错误结果,故 %(km)(其实只要是k,m的公倍数都可以)
为了方便起见建议用string来储存运算符(注意输出时的代码格式)
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
ll n, m, k;
int vis[1000001];
struct node
{
string s;
ll num;
int step;
};
void bfs()
{
queue<node> q;
node st, next, now;
st.step = 0;
st.num = n;
st.s = "";
q.push(st);
memset(vis, 0, sizeof vis);
vis[(n % (m * k) + (m * k)) % (m * k)] = 1;
while(!q.empty())
{
now = q.front();
q.pop();
if( ( now.num%k + k ) % k == ( (n+1)%k + k ) % k )//(n+1) % k
{
printf("%d\n", now.step);
cout<<now.s<<endl;
return;
}
for (int i = 1; i <= 4; i++)//n k m
{
ll temp;
next = now;
next.step = now.step + 1;
switch(i)
{
case 1://加
{
temp = next.num + m;
next.num = (temp%(m*k) + (m*k)) % (m*k);//temp % (m*k)
//↑ 对大数的处理-取模
//%(m*k)是对%m的情况特殊处理
next.s += "+";
break;
}
case 2://减
{
temp = next.num - m;
next.num = (temp%(m*k) + (m*k)) % (m*k);
next.s += "-";
break;
}
case 3://乘
{
temp = next.num * m;
next.num = (temp%(m*k) + (m*k)) % (m*k);
next.s += "*";
break;
}
case 4://mod
{
temp = (next.num % m + m) % m;//next.num % m
next.num = (temp%(m*k) + (m*k)) % (m*k);
next.s += "%";
break;
}
}
if(!vis[next.num])
{
vis[next.num] = 1;
q.push(next);
}
}
}
puts("0");
return;
}
int main()
{
scanf("%lld %lld %lld", &n, &k, &m);
while(n||m||k)
{
bfs();
scanf("%lld %lld %lld", &n, &k, &m);
}
return 0;
}