挑战程序竞赛系列(40):4.1模运算的世界(3)
挑战程序竞赛系列(40):4.1模运算的世界(3)详细代码可以fork下Github上leetcode项目,不定期更新。练习题如下:POJ 2115: C LooooopsPOJ 2115: C Looooops题目的Loooo…有点长啊,哈哈。此题的思路很简单,只要列出一个式子即可,如下:(A+CX)≡Bmod 2k(A + CX) \equiv B \mod \space 2^
挑战程序竞赛系列(40):4.1模运算的世界(3)
详细代码可以fork下Github上leetcode项目,不定期更新。
练习题如下:
POJ 2115: C Looooops
题目的Loooo…有点长啊,哈哈。
此题的思路很简单,只要列出一个式子即可,如下:
整理一下,即求同余表达式 CX≡(B−A)mod 2k
那么问题就转换成同余表达式如何求解了?可以参考《挑战》P291关于逆元的介绍,这里给出自己的求解思路。
首先,同余表达式可能有解,也可能无解,就拿式子 ax≡bmodm 而言,我们可以写成如下表达式: ax−my=b
所以为了该方程有解,必须满足d = gcd(a,m), b能够被d整除,否则等式左边将出现小数,一定无解。
既然判断了同余表达式是否有解,接下来就可以化为:
此时,因为 gcd(a/d,m/d)=1 ,满足 ax≡1modm 关于逆元的定义条件,一定存在解,我们可以求出逆元 x0=(a/d)−1
于是可以表示为:
对应的代码如下:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class Main{
String INPUT = "./data/judge/201708/P2115.txt";
public static void main(String[] args) throws IOException {
new Main().run();
}
void solve() {
while (true){
int A = ni();
int B = ni();
int C = ni();
int K = ni();
if (A + B + C + K == 0) break;
long ans = modular_linear_equation_solver(C, B - A, (long)1 << K);
if (ans == -1){
out.println("FOREVER");
}
else{
out.println(ans);
}
}
}
class Pair{
long d;
long x;
long y;
// a * x + b * y = d
public Pair(long d, long x, long y){
this.d = d;
this.x = x;
this.y = y;
}
}
public Pair extgcd(long a, long b){ // a > b or a < b
if (b == 0){
return new Pair(a, 1, 0);
}
else{
Pair p = extgcd(b, a % b);
Pair ans = new Pair(0, 0, 0);
ans.d = p.d;
ans.x = p.y;
ans.y = p.x - (a / b) * p.y;
return ans;
}
}
public long mod_inverse(long a, long m){
Pair p = extgcd(a, m);
if (p.d != 1) return -1;
return (p.x % m + m) % m;
}
public long modular_linear_equation_solver(long a, long b, long m){
Pair p = extgcd(a, m);
if (b % p.d != 0) return -1;
long x0 = mod_inverse(a / p.d, m / p.d);
return (x0 * (b / p.d) % (m / p.d) + (m / p.d)) % (m / p.d);
}
FastScanner in;
PrintWriter out;
void run() throws IOException {
boolean oj;
try {
oj = ! System.getProperty("user.dir").equals("F:\\java_workspace\\leetcode");
} catch (Exception e) {
oj = System.getProperty("ONLINE_JUDGE") != null;
}
InputStream is = oj ? System.in : new FileInputStream(new File(INPUT));
in = new FastScanner(is);
out = new PrintWriter(System.out);
long s = System.currentTimeMillis();
solve();
out.flush();
if (!oj){
System.out.println("[" + (System.currentTimeMillis() - s) + "ms]");
}
}
public boolean more(){
return in.hasNext();
}
public int ni(){
return in.nextInt();
}
public long nl(){
return in.nextLong();
}
public double nd(){
return in.nextDouble();
}
public String ns(){
return in.nextString();
}
public char nc(){
return in.nextChar();
}
class FastScanner {
BufferedReader br;
StringTokenizer st;
boolean hasNext;
public FastScanner(InputStream is) throws IOException {
br = new BufferedReader(new InputStreamReader(is));
hasNext = true;
}
public String nextToken() {
while (st == null || !st.hasMoreTokens()) {
try {
st = new StringTokenizer(br.readLine());
} catch (Exception e) {
hasNext = false;
return "##";
}
}
return st.nextToken();
}
String next = null;
public boolean hasNext(){
next = nextToken();
return hasNext;
}
public int nextInt() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Integer.parseInt(more);
}
public long nextLong() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Long.parseLong(more);
}
public double nextDouble() {
if (next == null){
hasNext();
}
String more = next;
next = null;
return Double.parseDouble(more);
}
public String nextString(){
if (next == null){
hasNext();
}
String more = next;
next = null;
return more;
}
public char nextChar(){
if (next == null){
hasNext();
}
String more = next;
next = null;
return more.charAt(0);
}
}
}
注意:逆元和同余方程的解都有可能为负,所以需要加mod处理,注意下。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)