版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1435855
挑战程序竞赛系列(40):4.1模运算的世界(3)
详细代码可以fork下Github上leetcode项目,不定期更新。
练习题如下:
- POJ 2115: C Looooops
POJ 2115: C Looooops
题目的Loooo…有点长啊,哈哈。
此题的思路很简单,只要列出一个式子即可,如下:
(A CX)≡Bmod 2k
(A CX) equiv B mod space 2^k
整理一下,即求同余表达式CX≡(B−A)mod 2kCX equiv (B - A) mod space 2^k
那么问题就转换成同余表达式如何求解了?可以参考《挑战》P291关于逆元的介绍,这里给出自己的求解思路。
首先,同余表达式可能有解,也可能无解,就拿式子ax≡bmodmax equiv b mod m而言,我们可以写成如下表达式:ax−my=bax - my = b
所以为了该方程有解,必须满足d = gcd(a,m), b能够被d整除,否则等式左边将出现小数,一定无解。
既然判断了同余表达式是否有解,接下来就可以化为:
d=gcd(a,m)(a/d)x≡(b/d)modm/d
d = gcd(a, m) (a / d) x equiv(b / d) mod m / d
此时,因为gcd(a/d,m/d)=1gcd(a/d, m/d) = 1,满足ax≡1modmax equiv 1 mod m关于逆元的定义条件,一定存在解,我们可以求出逆元x0=(a/d)−1x_0 = (a / d)^{-1}
于是可以表示为:
(a/d)x≡(b/d)modm/dx≡(a/d)−1(b/d)modm/d
(a / d) x equiv(b / d) mod m / d x equiv (a/d)^{-1}(b/d) mod m / d
对应的代码如下:
代码语言:javascript复制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处理,注意下。