প্রদত্ত দুটি এবং পূর্ণসংখ্যার A এবং B এর জন্য এক্স এবং Y সংখ্যার একটি জোড় আবিষ্কার করুন যা A = X * Y এবং B = X xor Y


22

আমি এই সমস্যাটির সাথে লড়াই করছি আমি একটি প্রতিযোগিতামূলক প্রোগ্রামিং বইয়ের সন্ধান করেছি, তবে কীভাবে সমাধান করা যায় তার সমাধান ছাড়াই।

প্রদত্ত দুটি পূর্ণসংখ্যার জন্য এবং বি (64৪-বিট পূর্ণসংখ্যার ধরণের ক্ষেত্রে ফিট করতে পারে), যেখানে A বিজোড় হয় , সেখানে এক্স এবং ওয়াইয়ের সংখ্যার একটি জোড়া খুঁজে বার করুন যে A = X * Y এবং B = X xor Y. আমার পদ্ধতির তালিকাটি ছিল একটি সব ভাজক এবং সংখ্যাবৃদ্ধি পর্যন্ত বর্গমূল (ক) উপর সংখ্যার বর্গমূল (ক) এর অধীন সংখ্যা যুক্ত করার যে চেষ্টা একটি এবং যদি তাদের XOR সমান দেখতে বি । তবে আমি জানি না যে এটি যথেষ্ট দক্ষ কিনা। এই সমস্যার ভাল সমাধান / অ্যালগরিদম কী হবে?


1
একটি পূর্ণসংখ্যা অপারেটর এবং বিটওয়াস অপারেটরটি মিশ্রিত করা অদ্ভুত। আসলেই X*Yনাকি X&Y?
এরিক ডুমিনিল

এটি গুণ। (*)
এস্টার ডাব্লু।

এই কাজটি সমাধান করার জন্য আপনি কি ইতিমধ্যে কোনও লাইন কোড লিখেছেন? আপনি কোন প্রোগ্রামিং ভাষাটি ব্যবহার করতে চান?
লিংক 242

উত্তর:


5

এখানে একটি সাধারণ পুনরাবৃত্তি যা আমাদের জানা বিধিগুলি পর্যবেক্ষণ করে: (1) এক্স এবং ওয়াই উভয়ের কমপক্ষে উল্লেখযোগ্য বিটগুলি সেট করা হয়েছে যেহেতু কেবলমাত্র বিজোড় গুণগুলি একটি বিজোড় একাধিক ফলন করে; (২) যদি আমরা বি এর সর্বাধিক সেট বিট রাখতে এক্স সেট করি তবে ওয়াই স্কয়ার্ট (এ) এর চেয়ে বড় হতে পারে না; এবং (3) বি বা বর্তমান বিট অনুসারে এক্স বা ওয়াইতে বিট সেট করুন

নীচের পাইথন কোডটির ফলস্বরূপ আমি ম্যাট টিমারম্যানসের উদাহরণ কোড থেকে যে এলোমেলো জোড় বেছে নিয়েছি তা ছাড়া সকলের জন্য 300 টি পুনরাবৃত্তির নীচে । তবে প্রথমটি 231,199 টি পুনরাবৃত্তি গ্রহণ করেছে :)

from math import sqrt

def f(A, B):
  i = 64
  while not ((1<<i) & B):
    i = i - 1
  X = 1 | (1 << i)

  sqrtA = int(sqrt(A))

  j = 64
  while not ((1<<j) & sqrtA):
    j = j - 1

  if (j > i):
    i = j + 1

  memo = {"it": 0, "stop": False, "solution": []}

  def g(b, x, y):
    memo["it"] = memo["it"] + 1
    if memo["stop"]:
      return []

    if y > sqrtA or y * x > A:
      return []

    if b == 0:
      if x * y == A:
        memo["solution"].append((x, y))
        memo["stop"] = True
        return [(x, y)]
      else:
        return []

    bit = 1 << b

    if B & bit:
      return g(b - 1, x, y | bit) + g(b - 1, x | bit, y)
    else:
      return g(b - 1, x | bit, y | bit) + g(b - 1, x, y)

  g(i - 1, X, 1)
  return memo

vals = [
  (6872997084689100999, 2637233646), # 1048 checks with Matt's code
  (3461781732514363153, 262193934464), # 8756 checks with Matt's code
  (931590259044275343, 5343859294), # 4628 checks with Matt's code
  (2390503072583010999, 22219728382), # 5188 checks with Matt's code
  (412975927819062465, 9399702487040), # 8324 checks with Matt's code
  (9105477787064988985, 211755297373604352), # 3204 checks with Matt's code
  (4978113409908739575,67966612030), # 5232 checks with Matt's code
  (6175356111962773143,1264664368613886), # 3756 checks with Matt's code
  (648518352783802375, 6) # B smaller than sqrt(A)
]

for A, B in vals:
  memo = f(A, B)
  [(x, y)] = memo["solution"]
  print "x, y: %s, %s" % (x, y)
  print "A:   %s" % A
  print "x*y: %s" % (x * y)
  print "B:   %s" % B
  print "x^y: %s" % (x ^ y)
  print "%s iterations" % memo["it"]
  print ""

আউটপুট:

x, y: 4251585939, 1616572541
A:   6872997084689100999
x*y: 6872997084689100999
B:   2637233646
x^y: 2637233646
231199 iterations

x, y: 262180735447, 13203799
A:   3461781732514363153
x*y: 3461781732514363153
B:   262193934464
x^y: 262193934464
73 iterations

x, y: 5171068311, 180154313
A:   931590259044275343
x*y: 931590259044275343
B:   5343859294
x^y: 5343859294
257 iterations

x, y: 22180179939, 107776541
A:   2390503072583010999
x*y: 2390503072583010999
B:   22219728382
x^y: 22219728382
67 iterations

x, y: 9399702465439, 43935
A:   412975927819062465
x*y: 412975927819062465
B:   9399702487040
x^y: 9399702487040
85 iterations

x, y: 211755297373604395, 43
A:   9105477787064988985
x*y: 9105477787064988985
B:   211755297373604352
x^y: 211755297373604352
113 iterations

x, y: 68039759325, 73164771
A:   4978113409908739575
x*y: 4978113409908739575
B:   67966612030
x^y: 67966612030
69 iterations

x, y: 1264664368618221, 4883
A:   6175356111962773143
x*y: 6175356111962773143
B:   1264664368613886
x^y: 1264664368613886
99 iterations

x, y: 805306375, 805306369
A:   648518352783802375
x*y: 648518352783802375
B:   6
x^y: 6
59 iterations

বি <স্কয়ার্ট (এ), উদাহরণস্বরূপ, যখন এক্স == ওয়াই
ম্যাট টিমমারম্যানস

এক্স == ওয়াই কেবল সহজ উদাহরণ। বি যে কোনও সংখ্যা হতে পারে <স্কয়ার্ট (এ), যেমন এক্স = 0x300000011, ওয়াই = 0x30000007, এ = এক্স * ওয়াই, বি = 6
ম্যাট টিমমারম্যানস

পছন্দ করুন আমি পরীক্ষাগুলিতে হ্যান্ডলিং এবং আপনার উদাহরণ যুক্ত করেছি, যা 59 পুনরাবৃত্তিতে সমাধান হয়। আপনি যদি অন্য সমস্যাগুলি খুঁজে পান (বা যদি এই সমস্যাটি সমাধান না করা মনে হয়) তবে দয়া করে আমাকে জানান।
26

মজাদার. আপনি যখন এটির কাজ পেয়েছেন তখন আমি ব্যয়বহুল হয়ে উঠব was আমরা জানি যে 231199 এর থেকে ব্যয়বহুল মামলা রয়েছে তবে এগুলির বৈশিষ্ট্য নির্ধারণ করা কঠিন হয়ে পড়েছে। যাইহোক এটি দেখে মনে হচ্ছে এটি এখন ভাল কাজ করে।
ম্যাট টিমারম্যানস

9

আপনি জানেন যে কমপক্ষে একটি ফ্যাক্টর হ'ল <= স্কয়ার্ট (এ)। এটি একটি এক্স করা যাক।

বিটগুলিতে এক্সের দৈর্ঘ্য এ এর ​​দৈর্ঘ্যের প্রায় অর্ধেক হবে

এক্স এর উপরের বিটগুলি, সুতরাং - বর্গক্ষেত্র (এ) এর চেয়ে বেশি মানের --গুলি সমস্ত 0 হয় এবং বি এর সাথে সম্পর্কিত বিটগুলির ওয়াইয়ের সাথে সম্পর্কিত বিটের সমান মান থাকতে হবে।

Y এর উপরের বিটগুলি জানার সাথে সাথে আপনাকে সংশ্লিষ্ট ফ্যাক্টর এক্স = এ / ওয়াইয়ের জন্য একটি দুর্দান্ত ছোট পরিসীমা দেয়। যথাক্রমে Y এর জন্য বৃহত্তম এবং ক্ষুদ্রতম সম্ভাব্য মানের সাথে সামঞ্জস্য করে Xmin এবং Xmax গণনা করুন। মনে রাখবেন যে এক্সম্যাক্স অবশ্যই <= স্কয়ার্ট (এ) হতে হবে।

তারপরে কেবল এক্সমিন এবং এক্সম্যাক্সের মধ্যে সম্ভাব্য সমস্ত এক্স ব্যবহার করে দেখুন। খুব বেশি পরিমাণে থাকবে না, তাই এটি খুব বেশি সময় নেয় না।


চমৎকার সমাধান! এরকম কতগুলি এক্সের উপস্থিতি রয়েছে তার কি কোনও আবদ্ধ আছে?
কিয়ামজ

এটি সর্বাধিক বর্গক্ষেত্র (ক) / 2 এর ক্ষেত্রে যেখানে ওয়াইয়ের উপরের বিটগুলি সমস্ত 0 হয় them তবে এর মধ্যে খুব কম বিভাজনকারী হবে। যদি আপনি এটি নিয়ে উদ্বিগ্ন হন তবে আপনি ফেরমাটের
ম্যাট টিমর্ম্যানস

1
এটি একটি ভাল অন্তর্দৃষ্টি (+1), তবে আমরা যদি 64৪-বিট পূর্ণসংখ্যার কথা বলি তবে স্কয়ার্ট (এ) / ২ বিলিয়নেরও বেশি হতে পারে। দেখে মনে হচ্ছে এটি সাধারণত "প্রতিযোগিতামূলক প্রোগ্রামিং" পরিস্থিতিটির জন্য খুব ধীর হবে। (অস্বীকৃতি: আমি কোনও প্রোগ্রামিং প্রতিযোগিতা কখনও করি নি, সম্ভবত আমি এই সম্পর্কে ভুল করছি।) সম্ভবত আরও একটি অন্তর্দৃষ্টি রয়েছে যা এই এক সাথে একত্রিত হতে পারে?
রুখ

2
যদি আপনি পরিসীমাতে সম্ভাব্য বিভাজনগুলি খুঁজে পেতে ফর্ম্যাট পদ্ধতিটি ব্যবহার করেন তবে আমি মনে করি এটি স্কয়ার্ট (স্কয়ার্ট (এ)) হ্রাস পাবে, যা অবশ্যই ঠিক আছে
ম্যাট টিমর্ম্যানস

6

এই সমস্যা সমাধানের জন্য অন্যান্য সহজবোধ্য উপায় আসলে উপর নির্ভর নিম্ন এন XY এবং এক্স XOR ওয়াই এর বিট শুধুমাত্র নিম্ন নির্ভর এন X এবং ওয়াই এর বিট অতএব, আপনার জন্য কম সম্ভাব্য উত্তর ব্যবহার করতে পারেন এন সীমিত করতে বিট আপনার কাজ শেষ না হওয়া অবধি নীচের এন + 1 বিটের সম্ভাব্য উত্তরগুলি ।

আমি যে কাজ করেছি, দুর্ভাগ্যক্রমে, একক এন এর জন্য একাধিক সম্ভাবনা থাকতে পারে । আমি কত ঘন ঘন একটা হতে হবে জানি না অনেক সম্ভাবনার, কিন্তু এটা সম্ভবত খুব আদৌ প্রায়ই যদি না, তাই এই একটি প্রতিযোগিতামূলক প্রেক্ষাপটে জরিমানা হতে পারে। সম্ভাবনাময়ভাবে, কেবলমাত্র কয়েকটি সম্ভাবনা থাকবে, যেহেতু এন বিটগুলির জন্য একটি সমাধান সমান সম্ভাবনা সহ এন + 1 বিটের জন্য 0 বা দুটি সমাধান সরবরাহ করবে ।

এলোমেলো ইনপুট জন্য এটি বেশ ভাল কাজ করে বলে মনে হচ্ছে। এটি পরীক্ষার জন্য আমি যে কোডটি ব্যবহার করেছি তা এখানে:

public static void solve(long A, long B)
{
    List<Long> sols = new ArrayList<>();
    List<Long> prevSols = new ArrayList<>();
    sols.add(0L);
    long tests=0;
    System.out.print("Solving "+A+","+B+"... ");
    for (long bit=1; (A/bit)>=bit; bit<<=1)
    {
        tests += sols.size();
        {
            List<Long> t = prevSols;
            prevSols = sols;
            sols = t;
        }
        final long mask = bit|(bit-1);
        sols.clear();
        for (long prevx : prevSols)
        {
            long prevy = (prevx^B) & mask;
            if ((((prevx*prevy)^A)&mask) == 0)
            {
                sols.add(prevx);
            }
            long x = prevx | bit;
            long y = (x^B)&mask;
            if ((((x*y)^A)&mask) == 0)
            {
                sols.add(x);
            }
        }
    }
    tests += sols.size();
    {
        List<Long> t = prevSols;
        prevSols = sols;
        sols = t;
    }
    sols.clear();
    for (long testx: prevSols)
    {
        if (A/testx >= testx)
        {
            long testy = B^testx;
            if (testx * testy == A)
            {
                sols.add(testx);
            }
        }
    }

    System.out.println("" + tests + " checks -> X=" + sols);
}
public static void main(String[] args)
{
    Random rand = new Random();
    for (int range=Integer.MAX_VALUE; range > 32; range -= (range>>5))
    {
        long A = rand.nextLong() & Long.MAX_VALUE;
        long X = (rand.nextInt(range)) + 2L;
        X|=1;
        long Y = A/X;
        if (Y==0)
        {
            Y = rand.nextInt(65536);
        }
        Y|=1;
        solve(X*Y, X^Y);
    }
}

আপনি ফলাফলগুলি এখানে দেখতে পাবেন: https://ideone.com/cEuHkQ

দেখে মনে হচ্ছে এটি সাধারণত কয়েক হাজার চেক নেয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.