Consider an infinite complete binary tree where the root node is 1/1 and left and right childs of node p/q are p/(p+q) and (p+q)/q, respectively. This tree looks like:
It is known that every positive rational number appears exactly once in this tree. A level-order traversal of the tree results in the following array:
Please solve the following two questions:
Input:
The first line of the input gives the number of test cases, T. T test cases follow. Each test case consists of one line. The line contains a problem id (1 or 2) and one or two additional integers:
Output:
For each test case:
Limits:
1 ≤ T ≤ 100; p and q are relatively prime.
Small dataset
1 ≤ n, p, q ≤ 216-1; p/q is an element in a tree with level number ≤ 16.
Large dataset
1 ≤ n, p, q ≤ 264-1; p/q is an element in a tree with level number ≤ 64.
Sample:
One Solution:
針對第一個問題:
解問題的思維是當你能決定某個位置在 binary tree 走的路徑, 那接下來的運算就是簡單的加法. 假設父節點是 (p,q) 的話:
所以接下來便是決定 n-th 在 binary tree 走的路徑. 接著我們把 n 轉成二進位對應到原先 binary tree:
如此可以觀察到 0->往左邊; 1->往右邊 (紅色的數字可以忽略), 所以可以知道:
所以用來解問題一的類別設計如下:
- public static class P1{
- public long p=1;
- public long q=1;
- public void move(char c)
- {
- if(c=='0') q = p+q;
- else p = p+q;
- }
- @Override
- public String toString() {return String.format("%d %d", p,q);}
- }
至於問題二:
就使用反推的思維, 當 p>q 說明當上一次是由父節點的右邊移動; 如果 q>p 說明上一次是由父節點的左邊移動. 如此你可以得到行走的路徑, 跟據 0->往左邊; 1->往右邊 將之轉換成二進位後記得要反轉 (因為現在是倒著走 Orz). 所以問題二的類別如下:
- public static class P2{
- public long p=0;
- public long q=0;
- public P2(long p, long q){this.p = p; this.q = q;}
- public String run()
- {
- int loop=0;
- StringBuffer strBuf = new StringBuffer();
- while(true)
- {
- if(p==1 && q==1) break;
- else if(p>q)
- {
- strBuf.append("1");
- p = p-q;
- }
- else
- {
- strBuf.append("0");
- q = q-p;
- }
- loop++;
- if(loop==Integer.MAX_VALUE) System.err.printf("\t[Error] Exceed Int Max!\n");
- }
- if(loop==0) return "1";
- else {
- BigInteger bi1 = new BigInteger(new StringBuilder(strBuf.toString()).reverse().toString(), 2);
- BigInteger bi2 = new BigInteger("2");
- bi1.add(bi2.pow(loop));
- return bi1.add(bi2.pow(loop)).toString();
- }
- }
- }
- package cj2014;
- import java.math.BigInteger;
- import flib.util.io.QSReader;
- import flib.util.io.QSWriter;
- public class PB {
- public static class P1{
- public long p=1;
- public long q=1;
- public void move(char c)
- {
- if(c=='0') q = p+q;
- else p = p+q;
- }
- @Override
- public String toString() {return String.format("%d %d", p,q);}
- }
- public static class P2{
- public long p=0;
- public long q=0;
- public P2(long p, long q){this.p = p; this.q = q;}
- public String run()
- {
- int loop=0;
- StringBuffer strBuf = new StringBuffer();
- while(true)
- {
- if(p==1 && q==1) break;
- else if(p>q)
- {
- strBuf.append("1");
- p = p-q;
- }
- else
- {
- strBuf.append("0");
- q = q-p;
- }
- loop++;
- if(loop==Integer.MAX_VALUE) System.err.printf("\t[Error] Exceed Int Max!\n");
- }
- if(loop==0) return "1";
- else {
- BigInteger bi1 = new BigInteger(new StringBuilder(strBuf.toString()).reverse().toString(), 2);
- BigInteger bi2 = new BigInteger("2");
- bi1.add(bi2.pow(loop));
- return bi1.add(bi2.pow(loop)).toString();
- }
- }
- }
- /**
- * BD: https://code.google.com/codejam/contest/2924486/dashboard#s=p1
- * @param args
- */
- public static void main(String[] args) throws Exception{
- String fn="B-large-practice.in";
- QSReader qsr = new QSReader(String.format("data/2014/%s", fn));
- QSWriter qsw = new QSWriter(String.format("data/2014/%s.out", fn));
- qsr.open();
- Integer pc = Integer.valueOf(qsr.line());
- System.out.printf("\t[Info] Total %d question...\n", pc);
- for(int i=1; i<=pc; i++)
- {
- String ps[] = qsr.line().split(" ");
- if(ps[0].equals("1"))
- {
- // If the problem id is 1, then only one integer n is given,
- // and you are expected to find the n-th element of the array.
- try
- {
- char[] actions;
- actions = Long.toBinaryString(Long.valueOf(ps[1])).toCharArray();
- if(ps[1].length()>18) actions = new BigInteger(ps[1]).toString(2).toCharArray();
- else actions = Long.toBinaryString(Long.valueOf(ps[1])).toCharArray();
- P1 p1 = new P1();
- for(int j=1; j
- System.out.printf("\t\tP1: %s -> %s\n", ps[1], p1);
- qsw.line(String.format("Case #%d: %s", i, p1.toString()));
- }
- catch(Exception e)
- {
- System.out.printf("\t[Error] %s\n", e.toString());
- qsw.line(String.format("Case #%d: -1", i));
- }
- }
- else if(ps[0].equals("2"))
- {
- // If the problem id is 2,
- // then two integers p and q are given, and you are expected to find the position of p/q in the array.
- P2 p2 = new P2(Long.valueOf(ps[1]), Long.valueOf(ps[2]));
- String asw = p2.run();
- System.out.printf("\t\tP2: %s %s -> %s\n", ps[1], ps[2], asw);
- qsw.line(String.format("Case #%d: %s", i, asw));
- }
- }
- qsr.close();
- qsw.close();
- }
- }
* [ Java 文章收集 ] BigInteger 的使用
沒有留言:
張貼留言