প্রদত্ত ব্যাপ্তিতে সমস্ত সংখ্যার XOR সন্ধান করুন


99

আপনাকে একটি বিশাল পরিসর দেওয়া হয়েছে [a, b] যেখানে 'a' এবং 'b' সাধারণত 1 এবং 4,000,000,000 এর মধ্যে থাকতে পারে। আপনাকে প্রদত্ত ব্যাপ্তির সমস্ত সংখ্যার XOR বের করতে হবে।

এই সমস্যাটি টপকোডার এসআরএম-এ ব্যবহৃত হয়েছিল। আমি ম্যাচে জমা দেওয়া সমাধানগুলির মধ্যে একটি দেখেছি এবং এটি কীভাবে কাজ করছে তা অনুধাবন করতে পারছি না।

বিজয়ী সমাধানটি ব্যাখ্যা করতে কেউ সহায়তা করতে পারে:

long long f(long long a) {
     long long res[] = {a,1,a+1,0};
     return res[a%4];
}

long long getXor(long long a, long long b) {
     return f(b)^f(a-1);
}

এখানে, getXor()উত্তীর্ণ পরিসীমা [a, b] এবং "f ()" এর সমস্ত সংখ্যার জোরকে গণনা করার আসল ফাংশনটি হেল্পার ফাংশন।


আমি আপনার প্রশ্নটি কিছুটা সম্পাদনা করেছি। কিছু কোড কেন তা বোঝাতে আমরা আপত্তি করি না, তবে এটি সমাধানের জন্য আমাদের অন্যান্য পদ্ধতির নতুন তালিকার দরকার নেই। টপকোডার এ ছেড়ে দিন।
কেভ

@ কেভ কোন সমস্যা নেই! আমি লিখেছি যেহেতু কিছু লোক ইতিমধ্যে লিখিত জিনিসটি ব্যাখ্যা করার চেয়ে তাদের নিজস্ব উপায় দিতে পছন্দ করে। এবং কোনও নতুন ধারণা কখনই অপচয় নয় ...;)
rajneesh2k10

এটির জন্য a<=0বা এর জন্য অপরিবর্তিত আচরণ রয়েছে b<0long longএকটি স্বাক্ষরিত ধরণের, তাই x%4নেতিবাচক ইনপুটগুলির জন্য নেতিবাচক (বা 0) । সম্ভবত আপনি চান unsigned long long, এবং / অথবা a & 3অ্যারে সূচক?
পিটার কর্ডেস

উত্তর:


153

এটি একটি চমত্কার চালাক সমাধান - এটি চলমান XORs এ ফলাফলের একটি প্যাটার্ন রয়েছে যে সত্যটি কাজে লাগায়। f()ফাংশন থেকে XOR যাও মোট রান [0, একটি] হিসাব করে। 4-বিট সংখ্যার জন্য এই টেবিলটি একবার দেখুন:

0000 <- 0  [a]
0001 <- 1  [1]
0010 <- 3  [a+1]
0011 <- 0  [0]
0100 <- 4  [a]
0101 <- 1  [1]
0110 <- 7  [a+1]
0111 <- 0  [0]
1000 <- 8  [a]
1001 <- 1  [1]
1010 <- 11 [a+1]
1011 <- 0  [0]
1100 <- 12 [a]
1101 <- 1  [1]
1110 <- 15 [a+1]
1111 <- 0  [0]

যেখানে প্রথম কলামটি বাইনারি উপস্থাপনা এবং তারপরে দশমিক ফলাফল এবং এর সূচক (ক) এর সাথে এটি XOR তালিকার সাথে সম্পর্কিত। এটি ঘটে কারণ সমস্ত উপরের বিটগুলি বাতিল হয়ে যায় এবং প্রতি 4 সর্বনিম্ন দুটি বিট চক্র হয়,

এখন [a, b] এর একটি সাধারণ পরিসীমা বিবেচনা করুন। আমরা f()[0, a-1] এবং [0, খ] এর জন্য এক্সওআর খুঁজে পেতে ব্যবহার করতে পারি । যেহেতু নিজের সাথে এক্সওআর'র কোনও মান শূন্য, তাই এক্সওআর-এর f(a-1)সমস্ত মান কম বাদ দেয় aকেবলমাত্র আপনাকে রেঞ্জের [এ, বি] এর এক্সওর রেখে দেয় ।


মিনিট রেঞ্জের থ্রেশহোল্ডটি 1 নয়, 0
পঞ্চো ইলচেভ

4
@ পেঞ্চোএলচেভ এতে 0 টি অন্তর্ভুক্ত কিনা তা এক ধরণের শব্দের - (n ^ 0) == n
ফ্যাটালআরর

4
@ rajneesh2k10 ওয়েল, 4 রানের মধ্যে (4 টির একাধিক থেকে শুরু), সর্বনিম্ন ব্যতীত সমস্ত বিট একই, তাই তারা একে অপরকে বাতিল করা বা তাদের মূল মূল্য থাকা মধ্যে বিকল্প হয়। এটি সত্য যে প্রতি 2 প্রতি সর্বনিম্ন বিট চক্র হয় তবে 0 ^ 1 == 1 (অর্থাৎ তারা বাতিল করে না)। সর্বনিম্ন দুটি বিশেষ হওয়ার কারণটি হ'ল (00 ^ 01 ^ 10 ^ 11) == 00. অন্য কথায়, প্রতিটি 4 টি মান আপনার দ্বারা চালিত হয় এবং আপনাকে 0 এ ফিরে আসে এবং তাই আপনি এই জাতীয় সমস্ত চক্র বাতিল করতে পারেন, যা কেন একটি% 4 তাৎপর্যপূর্ণ।
ফ্যাটালআরার

4
@ পান্ড্রেই সেখানে aআছে ২ টি, ০ নয়
হেরোলেড

4
এই কলামটি চলছে চলমান জোর এবং 1 জোর 2 হল 3, সুতরাং সেই সারির বর্তমান মানটি আমার কাছে সঠিক দেখাচ্ছে।
ফ্যাটাল এরর

58

ফ্যাটালআরারের দুর্দান্ত উত্তরে যুক্ত করে লাইনটি return f(b)^f(a-1);আরও ভালভাবে ব্যাখ্যা করা যেতে পারে। সংক্ষেপে, এর কারণ XOR এর এই দুর্দান্ত বৈশিষ্ট্যগুলি রয়েছে:

  • এটা মিশুক - প্লেস বন্ধনী আপনি যেখানেই থাকুন না কেন আপনি চান
  • এটা পরিবহণযোগ্য - অর্থ আপনি অপারেটরদের চারদিকে সরিয়ে নিতে পারেন (তারা "যাত্রা" করতে পারেন)

এখানে উভয়ই কর্মক্ষম:

(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
  • এটা নিজেই বিপরীত হয়

এটার মত:

a ^ b = c
c ^ a = b

অন্যান্য সাহসী / পরিবহিত অপারেটরগুলির দুটি উদাহরণ হ'ল যোগ এবং গুণ করা, তবে তারা নিজেরাই বিপরীত হয় না। ঠিক আছে, তাই, কেন এই বৈশিষ্ট্যগুলি গুরুত্বপূর্ণ? ঠিক আছে, একটি সরল রুট হ'ল এটিকে প্রকৃতপক্ষে কীভাবে প্রসারিত করা যায় এবং তারপরে আপনি এই বৈশিষ্ট্যগুলি কর্মক্ষেত্রে দেখতে পাবেন।

প্রথমে আসুন আমরা যা চাই তা সংজ্ঞায়িত করি এবং এটিকে n বলি:

n      = (a ^ a+1 ^ a+2 .. ^ b)

এটি যদি সহায়তা করে তবে এক্সওআর (^) এর মতো মনে করুন যেন এটি অ্যাড was

আসুন ফাংশনটি সংজ্ঞায়িত করুন:

f(b)   = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b

bএর চেয়েও বড় a, তাই কেবলমাত্র কয়েকটি অতিরিক্ত বন্ধনীতে নিরাপদে ফেলে (যা আমরা এটির সহযোগী কারণ) আমরা এটিও বলতে পারি:

f(b)   = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)

যা এটিকে সরল করে:

f(b)   = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)

f(b)   = f(a-1) ^ n

এর পরে, আমরা আমাদের যাদু লাইনের জন্য সেই বিপরীত সম্পত্তি এবং চালচলন ব্যবহার করি:

n      = f(b) ^ f(a-1)

আপনি যদি কোনও অ্যাডের মতো এক্সওআর নিয়ে ভাবছিলেন, আপনি সেখানে একটি বিয়োগফল ফেলেছেন। এক্সওআর হ'ল এক্সওআরকে যোগকে বিয়োগ করতে হবে!

আমি কীভাবে এই বিষয়টি নিয়ে আসব?

লজিকাল অপারেটরগুলির বৈশিষ্ট্যগুলি মনে রাখবেন। তাদের সাথে প্রায় একটি অ্যাডের মতো কাজ করুন বা যদি এটি সাহায্য করে তবে গুণ করুন। এটি অস্বাভাবিক বোধ করে যে এবং (&), xor (^) এবং বা (|) সম্মিলিত, তবে তারা!

প্রথমে নিষ্পাপ বাস্তবায়ন চালান, আউটপুটে নিদর্শনগুলি দেখুন, তারপরে এমন নিয়মগুলি সন্ধান করুন যা প্যাটার্নটি সত্য তা নিশ্চিত করে। আপনার বাস্তবায়ন আরও সরল করুন এবং পুনরাবৃত্তি করুন। এটি সম্ভবত সেই মূল পথ যা মূল স্রষ্টা গ্রহণ করেছিলেন, এটি পুরোপুরি অনুকূল নয় (যেমন অ্যারের পরিবর্তে একটি স্যুইচ স্টেটমেন্ট ব্যবহার করুন) তা হাইলাইট করে।


4
এটি আমার বিচ্ছিন্ন গণিতের কোর্সটির স্মরণ করিয়ে দেয় যা আমি গত বছর বিশ্ববিদ্যালয়ে পড়েছিলাম। মজার দিন এটি পড়ার সাথে সাথে আমার মনে যা আসলো তা হ'ল এই এক্সকেসিডি কমিক
সান ফ্রান্সিস এন। বলাইস

3

আমি জানতে পেরেছি যে নীচের কোডটিও প্রশ্নের উত্তর দেওয়া সমাধানের মতো কাজ করছে।

এটি হতে পারে কিছুটা অপ্টিমাইজড তবে এটি পুনরাবৃত্তি পর্যবেক্ষণ থেকে যেমনটি পেয়েছি ঠিক তেমন গ্রহণযোগ্য উত্তরে দেওয়া হয়েছে,

আমি প্রদত্ত কোডের পিছনে গাণিতিক প্রমাণগুলি জানতে / বুঝতে চাই, যেমন @ লুক ব্রিগেস দ্বারা উত্তরে ব্যাখ্যা করা হয়েছে

এই যে জাভা কোড

public int findXORofRange(int m, int n) {
    int[] patternTracker;

    if(m % 2 == 0)
        patternTracker = new int[] {n, 1, n^1, 0};
    else
        patternTracker = new int[] {m, m^n, m-1, (m-1)^n};

    return patternTracker[(n-m) % 4];
}

2

আমি পুনরাবৃত্তি দিয়ে সমস্যার সমাধান করেছি। আমি কেবল প্রতিটি পুনরাবৃত্তির জন্য ডেটাসেটকে প্রায় সমান অংশে বিভক্ত করি।

public int recursion(int M, int N) {
    if (N - M == 1) {
        return M ^ N;
    } else {
        int pivot = this.calculatePivot(M, N);
        if (pivot + 1 == N) {
            return this.recursion(M, pivot) ^ N;
        } else {
            return this.recursion(M, pivot) ^ this.recursion(pivot + 1, N);
        }
    }
}
public int calculatePivot(int M, int N) {
    return (M + N) / 2;
}

সমাধান সম্পর্কে আপনার চিন্তা আমাকে জানাতে দিন। উন্নতি ফিডব্যাকস পেয়ে খুশি। প্রস্তাবিত সমাধানটি 0 (লগ এন) জটিলতায় XOR গণনা করে।

ধন্যবাদ


সাধারণ এম ^ (এম + 1) ^ ... ^ (এন -1) ^ n গণনার সাথে এটির একই কম্পিউটারের জটিলতা রয়েছে। এটি 0 (এন)।
আন আনগুইন

0

XOR কে 0 থেকে N পর্যন্ত সমর্থন করার জন্য প্রদত্ত কোডটি নীচের মত সংশোধন করতে হবে,

int f(int a) {
    int []res = {a, 1, a+1, 0};
    return res[a % 4];
}

int getXor(int a, int b) {
    return f(b) ^ f(a);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.