دایره عجیب


  • محدودیت زمان: ۲ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

حسنی و n1n - 1 نفر از دوستانش دور یک دایره نشستند و شروع به انجام بازی اتل‌متل kkتوله می‌کنند. شیوه انجام بازی این جوری هست که حسنی به عنوان نفر اول می‌گوید "سلام!". بعد از آن در هر مرحله نفر kk تا جلوتر نفر قبلی می‌گوید "سلام!". این روال ادامه دارد تا دوباره نوبت حسنی شود و آن موقع بازی تموم می‌شود.

حالا حسنی می‌خواهد بداند که این بازی چند مرحله طول می‌کشد و از آن‌جا که خیلی سرگرم بازی شده، از شما می‌خواهد تا جواب را به او بگویید.

ورودی🔗

در خط اول ورودی nn و kk آمده‌ است.

1kn1 0001 \le k \le n \le 1\ 000

خروجی🔗

در تنها خط خروجی تعداد مراحلی را که طول می‌کشد تا دوباره نوبت حسنی شود را چاپ کنید.

مثال🔗

ورودی نمونه ۱🔗

5 2
Plain text

خروجی نمونه ۱🔗

5
Plain text

اگر افراد دور دایره را از 11 تا 55 شماره‌گذاری کنیم به طوری که حسنی شماره یک را بگیرد طبق چنین روندی دوباره نوبت حسنی می‌شود:

(1,3,5,2,4,1)(1, 3, 5, 2, 4, 1)

ورودی نمونه ۲🔗

6 2
Plain text

خروجی نمونه ۲🔗

3
Plain text

در این حالت افرادی که سلام می‌کنند چنین شماره‌هایی را دارند:

(1,3,5,1) (1, 3, 5, 1)

ورودی نمونه ۳🔗

6 6
Plain text

خروجی نمونه ۳🔗

1
Plain text

در این حالت نفر kkتا بعدی حسنی خود حسنی است!


راهنمایی ۱

سعی کنید روند بازی را به صورت ساده، جوری که بتوانید کد آن را بزنید، در بیاورید.
برای مثال در سوال آمده است "تا زمانی که نوبت دوباره به حسنی نرسیده‌است، بازی ادامه دارد." که این همان حلقه است. (با این لینک می‌توانید بیشتر با حلقه آشنا شوید.)

راهنمایی ۲

فرض کنید دو متغیر cnt و cur دارید که در هر مرحله cnt برابر تعداد مراحل تا الان است و cur برابر اینکه اخرین نفری که گفت "سلام" چه کسی است.
برای مثال‌ها مراحل را اجرا کنید و مقدار cur و cnt را در هر مرحله یادداشت کنید.
فرض کنید که افراد را از ۰ تا n1n-1 شماره‌گذاری کردیم و حسنی شماره ۰ است.
مثلا برای ورودی نمونه ۲ که n=6n = 6 و k=2k=2 است به این شکل مقدار‌های متغیر بعد از هر مرحله تغییر می‌کند.

cnt cur
۱ ۰
۲ ۲
۳ ۴

و بعد از مرحله ۳ دوباره حسنی را می‌بینیم و بازی تمام می‌شود.

راهنمایی ۳

قسمت اصلی الگوریتم، یعنی شبیه‌سازی کردن بازی، از یک حلقه تشکیل شده است و دو متغیر cnt و curکه حلقه تا زمانی که بازی تمام نشده است، اجرا می‌شود.

شبه کد الگوریتم:

assign 0 to *cnt*
assign 0 to *cur*
while true :
    increase value of *cnt* by one
    update value of *cur*
    if *cur* = 0:
        break
Plain text

منظور از دستور break این است که از حلقه while بیرون بیاید و منظور از while true یعنی تا زمانی که به دستور break نرسیده است، حلقه را تکرار کند و منظور از assign 0 to *cnt* این است که مقدار متغیر cnt را برابر صفر بکن.

راه حل

می‌توانید مشاهده کنید که بعد هر مرحله cnt یک واحد زیاد می‌شود و cur باید برابر k-امین نفر جلو باشد. در صورتی که افراد را به ترتیب از 0 تا n1n-1 شماره گذاری کنید و حسنی 0 باشد. بعد هر مرحله cur به علاوه k می‌شود و سپس به پیمانه n باقی مانده گرفته می‌شود.

assign 0 to *cnt*
assign 0 to *cur*
while true :
    increase value of *cnt* by one
    assign (*cur* + *k*) to *cur*
    assign (*cur* mod *n*) to *cur*
    if *cur* = 0:
        break
Plain text

حسنی نگو عکاس بگو


  • محدودیت زمان: ۱ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

می‌توانید شعر زیر را نخوانید و تاثیری در فهم سوال ندارد.

توی ده شلمرود

حسنی تک و تنها بود

حسنی نگو بلا بگو

تنبل تنبل‌ها بگو

موی بلند، روی سیاه

ناخن دراز، واه و واه و واه

نه فلفی، نه قلقلی

نه مرغ زرد کاکلی

هیچکس باهاش رفیق نبود

تنها روی سه پایه، نشسته بود تو سایه

باباش می‌گفت: حسنی میای بریم حموم؟

«نه نمیام، نه نمیام»

سرت رو می‌خوای اصلاح کنی؟

«نه نمی‌خوام، نه نمی‌خوام»

کره الاغ کدخدا

یورتمه می‌رفت تو کوچه‌ها

«الاغه چرا یورتمه میری؟»

«دارم می‌رم بار ببرم

دیرم شده عجله دارم»

«الاغ خوب و نازنین

سر در هوا سم بر زمین

یالت بلند و پرمو

دمت مثال جارو

یک کمی به من سواری میدی؟»

«نه که نمی‌دم»

«چرا نمی‌دی؟»

«واسه این که من تمیزم

پیش همه عزیزم اما تو چی؟

موی بلند، روی سیاه

ناخن دراز، واه و واه و واه!»

غازه پرید تو استخر

«تو اردکی یا غازی؟»

«من غاز خوش زبانم»

«میای بریم به بازی؟»

«نه جانم»

«چرا نمیای؟»

«واسه این که من

صبح تا غروب

میون آب، کنار جو

مشغول کار و شستشو

اما تو چی؟

موی بلند، روی سیاه

ناخن دراز، واه و واه و واه»

در وا شد و یه جوجه

دوید و اومد تو کوچه

جیک‌جیک‌کنان

گردش‌زنان

اومد و اومد پیش حسنی

«جوجه کوچولو

کوچول موچولو

میای با من بازی کنی؟»

مادرش اومد «قدقدقدا

برو خونتون تو رو به خدا

جوجه‌ی ریزه میزه

ببین چقد تمیزه؟

اما تو چی؟

موی بلند، روی سیاه

ناخن دراز، واه و واه و واه»

حسنی با چشم گریون

پا شد و اومد تو میدون

«آی فلفلی، آی قلقلی

میاین با من بازی کنین؟»

«نه که نمیایم»

«چرا نمیاین؟»

فلفلی گفت:

من و داداشم و بابام و عموم

هفته‌ای دو بار میریم حموم

اما تو چی؟

قلقلی گفت: نگاش کنین

موی بلند، روی سیاه

ناخن دراز، واه و واه و واه

حسنی دویید پیش باباش

«حسنی میای بریم حموم؟»

«میام، میام»

«سرتو میخوای اصلاح کنی؟»

«میخوام، میخوام»

حسنی نگو یه دسته گل

تر و تمیز و تپل مپل

الاغ و خروس و جوجه غاز و ببعی

با فلفلی با قلقلی با مرغ زرد کاکلی

حلقه زدن دور حسن

الاغه می‌گفت:

اگر کاری نداری

بریم الاغ سواری

خروسه می‌گفت:

قوقولی قوقو، قوقولی قوقو

هر چی میخوای، فوری بگو

مرغه می‌گفت:

حسنی برو تو کوچه

بازی بکن با جوجه

غازه می‌گفت:

حسنی بیا با همدیگه بریم شنا

توی ده شلمرود

حسنی دیگه تنها نبود!


بعد از این که حسنی تمیز شد و با همه بازی کرد، همه دور هم جمع شدند و از بابای حسنی خواستند که ازشون عکس بگیره. ولی وقتی بابای حسنی اومد، فهمیدند که حداکثر kkتاشون درون یه عکس جا می‌شوند. بابای حسنی گفت: «خب حالا عیبی نداره، kkتا kkتا بیایید ازتون عکس می‌گیرم.»

مرغه گفت: «این‌طوری که نمی‌شه، من می‌خوام با جوجه‌هام توی یه عکس باشم.»

الاغه گفت: «تازه من هم می‌خوام با خروسه توی یه عکس باشم. اگه این‌طوریه، من اصلا عکس نمی‌گیرم.»

بابای حسنی یه ذره مِن‌و‌مِن کرد و گفت: «خب عیبی نداره. شما بیایید توی یه صف وایسید، بعد هم تا جایی که جا شدید می‌آیید توی عکس»

بالاخره اهالی ده شلمرود تصمیم گرفتند که به nnتا دسته تقسیم بشوند و توی دسته‌ی iiام aia_iنفر بودند که می‌خواستند با هم عکس بگیرند. حالا بابای حسنی از شما می‌پرسد که حداقل باید چند تا عکس بگیرد تا همه در یک عکس افتاده باشند.

در هر عکسی که بابای حسنی می‌گیرد یک بازه پشت سر هم از دسته‌ها می‌توانند حضور داشته باشند که جمع اعضای این بازه باید حداکثر kk باشد.

در واقع شما یه آرایه‌ی nnتایی دارید و باید بگید حداقل mm چقدر هست که بتوان آرایه‌ را به mm بازه تقسیم کرد که مجموع اعداد هر بازه حداکثر kk باشد.

توجه کنید که بازه به دنباله‌ای متوالی از اعضای یک آرایه گفته می‌شود.

ورودی🔗

ورودی شامل دو خط است. در خط اول به ترتیب ابتدا nn تعداد گروه‌ها و سپس kk حداکثر ظرفیت یک عکس به شما داده می‌شود.

در خط دوم nn عدد به شما داده می‌شود که عدد iiام آن‌ها، aia_i است.

1n,k100 000 1 \le n, k \le 100\ 000

0aik0 \le a_i \le k

خروجی🔗

خروجی برنامه شامل یک عدد صحیح است، حداقل تعداد عکس‌هایی که پدر حسنی باید بگیرد.

مثال🔗

ورودی نمونه ۱🔗

5 4
3 4 1 2 2
Plain text

خروجی نمونه ۱🔗

4
Plain text

بازه‌ها به صورت {3},{4},{1,2},{2}\{3\}, \{4\}, \{1, 2\}, \{2\} خواهند بود. یک جواب دیگر برای این مثال {3},{4},{1},{2,2}\{3\}, \{4\}, \{1\}, \{2, 2\} است.

ورودی نمونه ۲🔗

5 8
3 4 1 2 2
Plain text

خروجی نمونه ۲🔗

2
Plain text

راهنمایی ۱

اگر دسته اول و دوم نتوانند در یک عکس باشند، (یعنی a1+a2>ka_1+a_2 \gt k) حتما دسته اول باید تنهایی عکس بگیرند و با دسته دیگری نمی‌توانند در یک عکس باشند.

راهنمایی ۲

در چه صورت جواب بهینه‌ای وجود دارد که دسته اول و دوم هر دو در یک عکس باشند؟

راهنمایی ۳

ثابت کنید اگر دسته دوم می‌توانست در عکس با دسته اول باشد (یعنی a1+a2ka_1+a_2 \le k) جواب بهینه‌ای وجود دارد که دسته اول و دوم هر دو در یک عکس باشند.

راهنمایی ۴

اگر دسته اول و دوم با هم نمی‌توانستند در یک عکس باشند، یک عکس تکی از دسته اول بگیرید.
اگر دسته اول و دوم می‌توانستند با هم باشند، این دو دسته را یک دسته جدید با اندازه a1+a2a_1+a_2 در نظر بگیرید و مسئله را دوباره حل کنید.

راه حل

دسته اول را در عکس اول قرار بدهید. سپس دسته دوم را اگر می‌شد، در عکس قرار بدهید، سپس دسته سوم و به همین روال ادامه دهید تا زمانی که دیگر نمی‌توانید دسته جدیدی قرار بدهید.

فرض کنید t دسته اول را در عکس اول قرار دادید و نمی‌توانید دسته بعدی را در عکس قرار بدهید. حالا t دسته اول حذف شدند و با همین روش بقیه افراد را در عکس قرار بدهید.

در واقع از اولین دسته شروع کنید و تاجایی که می‌توانید دسته‌ها را در داخل عکس قرار بدهید.

اثبات درستی به صورت خلاصه این است که در هر مرحله اگر دسته‌ای رو می توانید قرار بدهید. دلیلی وجود ندارد که قرار ندهید و عکس بگیرید چون این دسته باید در عکس بعدی قرار بگیرد و می‌توانست در عکس اول باشد و در عکس دوم نباشد.
درستی الگوریتم را با استقرا نیز می‌توانید اثبات کنید چون دسته اول و دوم را در صورت امکان می‌توانید یک دسته بکنید و تعداد دسته‌ها کم می‌شود.

هارمه کناب


  • محدودیت زمان: ۳ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

حسنی برای این که در تابستان وقتش را تلف نکند به کسب و کار روی آورده و به تازگی بانکی به نام کناب تاسیس کرده است.
از آن‌جایی که دوست دارد شما نیز عضو کناب باشید به شما یک پروژه داده و خواسته تا همراه‌بانکی بنویسید که درخواست‌های زیر را اجرا کند.

1 ip:username
Plain text

این درخواست یعنی کاربری با نام‌ کاربری username و آی‌پی ip به همراه‌بانک وصل شد و در صورتی که username معتبر نباشد باید عبارت ‍‍‍invalid username را چاپ کنید.
به یک نام‌ کاربری معتبر می‌گوییم اگر فقط از حروف کوچک و بزرگ انگلیسی و اعداد تشکیل شده باشد.
برای مثال 1aAB2 معتبر است ولی ab*2 معتبر نیست.

2 ip:username:money
Plain text

این درخواست یعنی کاربری با آی‌پی ip به حسابی با نام‌ کاربری username به اندازه money پول ریخته‌ است. در واقع باید از حساب ip به اندازه money کم کنید و به حساب username اضافه کنید.

3 ip
Plain text

با داده شدن این درخواست مقدار پول داخل حساب فرد با آی‌پی ip را نمایش دهید.

(دقت کنید که پول هر فرد می‌تواند منفی هم بشود و هرکس در ابتدا ۰ واحد پول دارد)

ورودی🔗

در اولین خط ورودی عدد qq که بیانگر تعداد درخواست‌ها است به شما داده می‌شود و در qq خط بعد، در هر خط یک در‌خواست داده می‌شود.

در هر درخواست ابتدا type داده می‌شود که برابر یکی از اعداد ۱ یا ۲ یا ۳ است و اگر typetype برابر با ۱ باشد در ادامه دو رشته ip و username به شما داده می‌شود که توسط کاراکتر : از هم جدا شده‌اند. اگر typetype مساوی ۲ باشد سه رشته ip و username و money داده می‌شود که با : از هم جدا شده‌اند و اگر هم typetype مساوی ۳ باشد رشته ip داده می‌شود.

0q,money100 0000 \le q,money \le 100\ 000

طول username و ip حداکثر ۱۵ است.

تضمین می‌شود که:

  • یک کاربر دوبار به همراه بانک وصل نمی‌شود و آی‌پی و نام‌ کاربری هیچ دو فردی یکسان نیست.
  • در صورتی که نام کاربری معتبر نباشد تنها ممکن است کاراکترهای _ یا * یا # یا $ در آن به کار رفته باشد.
  • همه‌ی ورودی‌های نوع ۲ و ۳ معتبر هستند؛ یعنی کاربری با آی‌پی یا نام کاربری مشخص شده‌، وجود دارد.
  • همه ipها به صورت ۴ عدد بین ۰ تا ۲۵۵ هستند که با نقطه از هم جدا شده‌اند.
  • حداکثر پولی که یک نفر می‌تواند داشته باشد 10910^9 است.

خروجی🔗

برای هر درخواست نوع ۱ در صورتی که username معتبر نیست باید عبارت invalid username را چاپ کنید و برای هر درخواست نوع ۳ باید مقدار پول حساب فرد خواسته شده را چاپ کنید. (پاسخ هر درخواست را در یک خط جدید چاپ کنید.)

مثال🔗

ورودی نمونه🔗

9
1 46.51.16.72:SmsS
1 192.168.10.13:#hacker$user
1 131.41.61.213:faeila
2 46.51.16.72:faeila:1000
3 46.51.16.72
3 131.41.61.213
2 131.41.61.213:SmsS:500
3 46.51.16.72
3 131.41.61.213
Plain text

خروجی نمونه🔗

invalid username
-1000
1000
-500
500
Plain text

توضیحات:

  • نام کاربری #hacker$user معتبر نیست برای همین باید invalid username خروجی بدهید.

  • از حساب SmsS هزار واحد پول کم می‌شود و به حساب faeila اضافه می‌شود و حالا SmsS منفی هزار و faeila هزار واحد پول دارد.

  • از حساب faeila پانصد واحد کم می‌شود و حالا پانصد واحد پول دارد و SmsS منفی پانصد.


راهنمایی ۱

برای پیاده‌سازی تمیز این سوال می‌توانید از Regex یا عبارت باقاعده و Associative array یا آرایه انجمنی استفاده کنید.
می‌توانید این لینک را نیز برای پیدا کردن Associative array در زبان مورد نظرتان استفاده کنید.

راهنمایی ۲

سعید کنید Associative array‌ای بسازید که هر کاربر که اضافه شد، بتوان با استفاده از نام‌کاربری هر فرد، آی‌پی آن فرد را پیدا کرد.

راهنمایی ۳

حالا Associative array دیگری بسازید که با استفاده از آی‌پی هر فرد بتوان موجودی حساب آن فرد را پیدا کرد و یا تغییر داد.

راه حل

حالا می‌توانید با استفاده از آی‌پی یا نام‌کاربری به موجودی حساب هر فرد دسترسی داشته باشید و درخواست‌ها را انجام بدهید.

فرض کنید sender_ip برابر آی‌پی فردی است که پول واریز می‌کند و receiver_user برابر نام کاربری فردی است که پول دریافت می‌کند. می‌خواهیم دو مقدار receiver_money را که برابر پول حساب دریافت کننده است و همچنین sender_user و sender_money که نام کاربری و پول حساب واریز کننده است را پیدا کنیم.

و دو Associative array به نام‌های get_user و get_money داریم که با اولی می‌توان با دادن آی‌پی فرد نام کاربری آن را به دست آورد و با استفاده از دومی، با دادن نام کاربری فرد، مقدار پول حسابش را به دست آورد.

شبه کد الگوریتم برای اعمال کوئری‌های نوع اول:

ip = input ip address
user = input username
if user is valid :
    add {user, 0} to get_money
    add {ip, user} to get_user
Plain text

شبه کد الگوریتم برای اعمال کوئری‌های نوع دوم:

sender_ip = sender ip address
receiver_user = receiver username

sender_user = get username from get_user
reassign value of (money of sender_user) in get_money by specific value
reassign value of (money of receiver_user) in get_money by specific value
Plain text

مسیر عجیب


  • محدودیت زمان: ۲ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

در کشور(!) شلمرود، nn شهر وجود دارد که با mm جاده دوطرفه به هم وصل شده‌اند.‌ طول جاده iiام هم wiw_i کیلومتر است. حسنی یک الاغ هم دارد که با استفاده از آن می‌تواند با سرعت یک کیلومتر بر ساعت جاده‌ها را طی کند.

حسنی جدیدا یک قابلیت جدید پیدا کرده که با استفاده از آن می‌تواند طول همه جاده‌ها را یک کیلومتر کم کند. حسنی فقط می‌تواند این قابلیت را وقتی درون یک شهر هست استفاده کند و tit_i ساعت طول می‌کشد که از این قابلیت در راس ii-ام استفاده کند. هم‌چنین اگر با استفاده از این قابلیت طول یک جاده صفر بشود آن جاده از شلمرود حذف می‌شود و نمی‌توان از آن عبور کرد.

حالا حسنی از شما می‌پرسد که کم‌ترین زمانی که طول می‌کشد تا از شهر شماره 11 به شهر شماره nn برسه چه قدر هست و از آن‌جا که شما هم حسنی را خیلی دوست دارید باید جوابش را بدهید.

ورودی🔗

در خط اول ورودی nn و mm آمده‌ است. سپس در خط بعدی nn عدد آمده که عدد ii-ام tit_i را نشان می‌دهد. در هر یک از mm خط بعدی هم سه عدد آمده که دو سر جاده و وزن آن جاده را مشخص می‌کند.

1n,m,ti,wi1 0001 \le n, m, t_i, w_i \le 1\ 000

خروجی🔗

در تنها خط خروجی کمترین زمان برای رسیدن از شهر شماره 11 به شهر شماره nn را چاپ کنید. در صورتی هم که مسیری از شهر 11 به شهر nn وجود نداشته باشد -1 چاپ کنید.

مثال🔗

ورودی نمونه ۱🔗

3 2
1 1000 1000
1 2 100
2 3 100
Plain text

خروجی نمونه ۱🔗

101
Plain text

در این نمونه وقتی که در شهر یک هستیم 9999 بار از قابلیت استفاده می‌کنیم و بعد از آن طول هر دو جاده یک می‌شود. بعد از آن می‌توان بعد از دو ساعت به شهر شماره سه رسید.

ورودی نمونه ۲🔗

3 2
3 1 1000
1 2 100
2 3 100
Plain text

خروجی نمونه ۲🔗

200
Plain text

در این مثال بدون استفاده از قابلیت می‌توان بعد از 200200 ساعت به شهر 33 رسید.

ورودی نمونه ۳🔗

4 2
1 2 3 4
1 2 5
2 3 10
Plain text

خروجی نمونه ۳🔗

-1
Plain text

در این نمونه مسیری از شهر 11 به شهر 44 وجود ندارد.


راهنمایی ۱

برای حل این سوال باید الگوریتم Dijkstra را بلد باشید.

راهنمایی ۲

به مجموعه‌ای از شهر‌ها و جاده‌ها گراف می‌گوییم و منظور از راس همان شهر و از یال همان جاده است.

اگر فرض کنید گراف اولیه برابر GG باشد. گراف GiG_i را به این صورت تعریف کنید که راس‌ها و یال‌های آن متنظار با راس‌ها و یال‌های GG است ولی طول هر یال آن منهای i شده و اگر منفی می‌شد، حذف شده است.

می‌توانید مشاهده کنید که GG همان G0G_0 است.

راهنمایی ۳

با استفاده از GiG_i‌ها گرافی بسازید که مسئله شما صرفا به مسئله کوتاه ترین مسیر تبدیل شود و پیچیدگی دیگری نداشته باشد.

دقت کنید که اگر روی راس v در گراف GiG_i‌ باشید می‌توانید در مدت زمان tvt_v به راس متناظر v در گراف Gi+1G_{i+1} بروید.

راهنمایی ۴

می‌توانید مشاهده کنید که G1001G_{1001} هیچ یالی ندارد چون wi1 000w_i \le1\ 000

راه حل

می‌خواهیم گراف جدیدی بسازیم که از اتصال GiG_iهای مخلتف است.

به این صورت این گراف را می‌سازیم که برای هر i (0i<10000 \le i \lt 1000) و هر راس مثل v در GiG_i، آن را توسط یک یال یک طرفه با وزن tvt_v به شهر متناظرش در Gi+1G_{i+1} وصل می‌کنیم.

می‌توانید مشاهده کنید که جواب معادل کوتاه ترین مسیر از شهر 1 درG0G_0 به یکی از شهر‌های n در یکی از GiG_iها است که طول مسیر کمینه شود از طرفی G1001G_{1001} به بعد چون هیچ یالی ندارند نیازی بهشون نداریم پس تعداد راس‌های ما برابر 1001×n1001 \times n و تعداد یال‌ها حداکثر 1001×m1001 \times m است که الگوریتم Dijkstra می‌تواند جواب مسئله را پیدا کند.

جدی


  • محدودیت زمان:‌ ۱ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

بابای حسنی به حسنی سوالی را داده و به او گفته تا این سوال را حل کند. اما چون حسنی زیاد علاقه‌ای به حل سوال ندارد، از شما خواسته تا این سوال را برای او حل کنید.

آرایه‌ای به نام aa به طول n n داریم. می‌خواهیم بلندترین زیردنباله‌ای از آرایه را پیدا کنیم که صعودی-نزولی باشد.

حسنی به دنباله b0,b1,...,bk1 b_0, b_1, ... , b_{k-1\ } صعودی-نزولی می‌گوید اگر سه شرط زیر برای آن برقرار باشد:

  • به ازای برای هر ii فرد که 0<i<k1 0 \lt i \lt k-1 داشته باشیم : bi1<bi>bi+1  b_{i-1} \lt b_{i} \gt b_{i+1} \
  • به ازای برای هر ii زوج که 0<i<k1 0 \lt i \lt k-1 داشته باشیم : bi1>bi<bi+1  b_{i-1} \gt b_{i} \lt b_{i+1} \
  • برای ii برابر با صفر هم داشته باشیم: b0<b1b_0 \lt b_1

حال شما باید طول بلندترین زیردنباله‌ای از آرایه aa که صعودی-نزولی است را پیدا کنید و آن را چاپ کنید.

نکته: به آرایه bb یک زیردنباله از آرایه aa می‌گوییم اگر بتوان با حذف تعدادی عضو از آرایه aa به آرایه bb رسید.

ورودی🔗

در اولین خط ورودی عدد nn و در خط بعدی nn عدد امده است که عدد ii ام مقدار خانه ii ام آرایه است. 1n100 000 1 \le n \le 100\ 000 ai109 |a_i| \le 10^9

خروجی🔗

در تنها خط خروجی طول بلندترین زیردنباله صعودی-نزولی را بگویید.

مثال🔗

ورودی نمونه ۱🔗

7
5 1 9 2 3 6 2
Plain text

خروجی نمونه ۱🔗

5
Plain text

برای مثال دنباله <1,9,2,3,2><1, 9, 2, 3, 2> یکی از جواب‌های ممکن است.

ورودی نمونه ۲🔗

4
1 2 1 2
Plain text

خروجی نمونه ۲🔗

4
Plain text

در این حالت کل آرایه aa صعودی-نزولی است.

وروی نمونه ۳🔗

4
2 1 2 1
Plain text

خروجی نمونه ۳🔗

3
Plain text

راهنمایی ۱

اگر دو عنصر متوالی و مساوی وجود داشت، می‌توانیم یکی را به دلخواه حذف کنیم چون در جواب مسئله تاثیری ندارد.

اگر سه عنصر متوالی وجود داشته باشد که صعودی باشند یعنی اولی کمتر از دومی و دومی کمتر از سومی باشد می‌توانیم عنصر دوم را حذف کنیم. (چرا؟)

اثبات راهنمایی ۱

اگر دنبال بهینه‌ای وجود داشته باشد که عنصر وسط (یعنی دوم) در این دنباله باشد طبق تعریف دنباله صعودی-نزولی، ممکن نیست هر سه عنصر در این دنباله باشند. پس می‌توان جای عنصر دوم یکی از دو عنصر که استفاده نشده را قرار داد. (در صورتی که این عنصر، اندیس فرد داشت جای آن عنصر بعدی که بزرگ‌تر است (و در نتیجه بهتر است) را قرار می‌دهیم و در غیر این صورت عنصر دیگر)

راهنمایی ۲

اگر k عنصر متوالی صعودی وجود داشت طبق راهنمایی قبل فقط اولی و اخری را نگه می‌داریم و بقیه را حذف می‌کنیم.
همینطوری اگر k عنصر متوالی نزولی وجود داشت اولی و اخری را نگه می‌داریم و بقیه را حذف می‌کنیم.

راه حل

بعد از حذف عنصر‌های اضافه که در راهنمایی ۲ گفته شد، می‌توانید مشاهده کنید که دنباله باقی‌مانده، یک دنباله صعودی-نزولی است. البته ممکن است نیاز باشد اولین عنصر را نیز حذف کنید در صورتی که عنصر اولی بزرگتر از عنصر بعدی باشد.

دنباله جدید صعودی - نزولی است چون عضو دوم بزرگتر از عضو اول است و اگر عنصر سوم بزرگتر از دومی باشد سه عنصر متوالی صعودی پیدا شده که تناقض دارد. پس عنصر سوم کوچک‌تر از عنصر دومی است. حالا اگر عنصر چهارم کوچک‌تر از عنصر سوم باشد دوباره سه عنصر متوالی نزولی پیدا شده که تناقض دارد پس عنصر چهارم بزرگ‌تر از عنصر سوم است.
اگر همین روال را ادامه بدهیم می‌بینیم که دنباله صعودی-نزولی است.

از طرفی این دنباله بلندترین است چون دنبال بهینه‌ای وجود داشته باشد که عنصر وسط (یعنی دوم) در این دنباله باشد طبق تعریف دنباله صعودی-نزولی ممکن نیست هر سه عنصر در این دنباله باشند پس می‌توان جای عنصر دوم یکی از دو عنصر که استفاده نشده را قرار داد (در صورتی که این عنصر، اندیس فرد داشت جای آن عنصر بعدی که بزرگ‌تر است (و در نتیجه بهتر است) را قرار می‌دهیم و در غیر این صورت عنصر دیگر)

دریچه


  • محدودیت زمان: ۳ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

آرایه aa، شامل اعداد a1,a2,...,an a_1, a_2, ..., a_n\ روی تخته نوشته شده است. در هر گام می‌توانیم یکی از دو عملیات زیر را انجام دهیم.

  • یک عدد xx از روی تخته در نظر بگیریم و تمام اعداد xx روی تخته را با x2\left \lfloor{ \frac {x}{2}}\right \rfloor جایگزین کنیم. (یعنی به جای هر xx روی تخته، x2\left \lfloor{ \frac {x}{2}}\right \rfloor قرار می‌دهیم.‌)
  • یک عدد xx از روی تخته در نظر بگیریم و تمام اعداد xx روی تخته را پاک کنیم.

از عملیات نوع دوم حداکثر kk بار می‌توانیم استفاده کنیم.

کم‌ترین تعداد مرحله برای این که در انتها کلا عددی روی تخته باقی نماند، یا تمامی اعداد باقی مانده برابر با 00 باشد، چه‌قدر است؟

ورودی🔗

ورودی شامل دو خط است که خط اول آن شامل دو عدد n,kn, k است.

در خط دوم nn عدد a1,a2,..,an a_1, a_2, .., a_n\ می‌آید که اعداد اولیه روی تخته را مشخص می‌کند.

1n100 0001 \le n \le 100\ 000 0k100 \le k \le 10 1ai1091 \le a_i \le 10^9

خروجی🔗

در تنها خط خروجی کمترین مراحل مورد نیاز برای رسیدن به شرایط مطلوب را چاپ کنید.

مثال🔗

ورودی نمونه ۱🔗

5 2
1 2 3 4 5
Plain text

خروجی نمونه ۱🔗

5
Plain text

یکی از روش‌ها این است که ابتدا اعداد 55 و 44 را با عملیات نوع اول به 22 تبدیل کنیم. سپس عدد 33 را به 11 تبدیل کنیم، اعداد روی تخته <1,2,1,2,2><1, 2, 1, 2, 2> خواهند بود. در نهایت عدد 1,21, 2 را پاک کنیم و دنباله تهی می‌شود. در مجموع 55 عملیات انجام شده است.

ورودی نمونه ۲🔗

4 1
1 1 2 3
Plain text

خروجی نمونه ۲🔗

3
Plain text

در یکی از روش‌های بهینه ابتدا عدد 33 را حذف می‌کنیم،‌ سپس 22 را با عملیات اول به 11 تبدیل می‌کنیم و نهایتا همه اعداد 11 را با عملیات اول به صفر تبدیل می‌کنیم.

ورودی نمونه ۳🔗

10 3
10 20 30 40 50 60 70 80 90 100
Plain text

خروجی نمونه ۳🔗

16
Plain text

راهنمایی ۱

در این بخش فرض کنید k=0k=0 است.

نمایش باینری اعداد را در نظر بگیرید، با عملیات اول آخرین رقم نمایش دودویی حذف می‌شود. اکنون درخت ترای اعداد آرایه را در نظر بگیرید، هدف این است که با حذف آخرین رقم همه اعداد را به صفر تبدیل کنیم که یعنی درخت ترای اعدادمان را تک راسی کنیم، پس می‌توان دریافت که به حداقل به اندازه تعداد راس‌های ترای منهای یک، عملیات نیاز داریم، چون در هر عملیات حداکثر یک راس حذف می‌شود.

همین‌طور می‌توان روشی ارائه داد تا با دقیقا همین تعداد عملیات، همه اعداد را به صفر تبدیل کنیم.

پس مساله در حالت k=0k=0، حل شد. سعی کنید با همین ایده مساله را برای k>0k>0 حل کنید.

راهنمایی ۲

در این بخش به بیان ایده حالت کلی مساله می‌پردازیم.

با استفاده از برنامه‌نویسی پویا روی درخت ترای مساله را حل می‌کنیم. فرض کنید بخواهیم برای هر راس در درخت ترای مثل vv (که متناظر با یک عدد است) ، مساله را برای اعداد درون زیردرخت آن راس حل کنیم، یعنی بخواهیم با jj عملیات حذف 1jk1 \le j \le k ، اعداد درون زیردرخت vv را به vv تبدیل کنیم.

برای محاسبه این مقادیر به این نتیجه می‌رسیم که لازم است روی این که آیا همه اعداد زیردرخت حذف شده‌اند یا خیر حالت‌بندی کنیم در نتیجه لازم است آرایه dpdpای‌داشته باشیم که dp[v][j][t]dp[v][j][t] کمترین تعداد عملیات‌های نوع اول لازم برای اینکه اعداد درون زیردرخت vv را به vv تبدیل کنیم و حداکثر jj بار ار عملیات حذف استفاده کنیم. هم‌چنین اگر t=0t=0 تضمین می‌شود که همه اعداد درون این زیردرخت حذف شده‌اند و هیچ عددی باقی نمانده است و درحالت t=1t=1، ممکن است تعدادی از اعداد (طبیعتا همگی vv هستند)، باقی بمانند.

راه حل

در این بخش شیوه پرکردن آرایه dpdp را شرح می‌دهیم.

فرض کنید بخواهیم dp[v][j][t]dp[v][j][t] را محاسبه کنیم.

فرزند چپ vv را vlv_l و فرزند راست آن‌ را vrv_r بنامید.

حالت بندی کنید که چه تعداد عملیات حذف را در زیردرخت vlv_l و چه تعداد را در زیر درخت vrv_r استفاده کنیم، هم‌چنین با حالت بندی روی اینکه در هر کدام از زیردرخت‌ها کل اعداد حذف شده‌اند یا خیر، می‌توان دریافت که یک عملیات اضافه برای تبدیل vlv_l و یا vrv_r به vv نیاز داریم یا خیر.

هم‌چنین یک حالت این است که روی vv عملیات حذف را انجام دهیم که نباید آن را فراموش کنید.

در نهایت پیچیدگی نهایی حل این مساله θ(nk2log2Ai)\theta (n k^2 \log_2 A_i) خواهد بود.

جهمه


  • محدودیت زمان: ۲ ثانیه
  • محدودیت حافظه: ۲۵۶ مگابایت

اگر دنباله‌ای از اعداد داشته باشید به اولین عدد طبیعی‌ای که در آن ظاهر نشده Mex آن دنباله می‌گوییم.
برای مثال Mex دنباله (1,2,5,9)(1, 2, 5, 9) برابر 33 و Mex دنباله (2,5)(2, 5) برابر 11 است.

دنباله a1,a2,a3,...,an a_1, a_2, a_3,...,a_n\ به شما داده شده است و باید جمع Mex تمام زیربازه‌های آن را به دست بیاورید. (در مجموع n(n+1)2\frac{n(n+1)}{2} زیربازه داریم.)

در واقع اگر  Mexi,j\ Mex_{i,j}‌را برابر Mex زیر دنباله (ai,ai+1,...,aj) (a_i,a_{i+1},...,a_j)\ تعریف کنیم، شما باید مقدار زیر را چاپ کنید. i=1n j=inMexi,j\sum_{i=1}^{n}\ \sum_{j=i}^{n} Mex_{i,j}

ورودی🔗

در سطر اول ورودی عدد nn و در سطر دوم nn عدد به شما داده می‌شود که عدد ii-ام برابر عضو ii ام دنباله است.

1n,ai100 0001 \le n, a_i \le 100\ 000

خروجی🔗

در تنها خط خروجی مقدار خواسته شده را نمایش دهید.

مثال🔗

ورودی نمونه ۱🔗

5
1 2 3 4 5
Plain text

خروجی نمونه ۱🔗

30
Plain text

توضیح:

Mex1,1=2Mex_{1,1} = 2
Mex1,2=3Mex_{1,2} = 3
Mex1,3=4Mex_{1,3} = 4
Mex1,4=5Mex_{1,4} = 5
Mex1,5=6Mex_{1,5} = 6

و Mex زیربازه‌هایی که ۱ را ندارند برابر ۱ است.

ورودی نمونه ۲🔗

8
2 1 4 2 1 3 2 1
Plain text

خروجی نمونه ۲🔗

113
Plain text

راهنمایی ۱

فرض کنید برای هر پیشوند از ارایه Mex را به دست آوردید. حالا عنصر اول را حذف کنید و Mex هر پیشوند را حساب کنید.

راهنمایی ۲

بعد از حذف عنصر اول، پیشنود‌هایی که Mex آن کمتر از a1a_1 بودند تغییری نمی‌کنند.

راهنمایی ۳

بعد از حذف عنصر اول در صورتی که Mex پیشنوندی قرار باشد تغییر کند، مقدار آن برابر a1a_1​ می‌شود.

راه حل

اگر mim_i برابر Mex پیشوندی باشد که به i ختم می شود. می‌توانید مشاهده کنید که دنباله زیر صعودی است:

m1m2m3...mn m_1 \le m_2 \le m_3 \le ... \le m_n

و وقتی عنصر اول را حذف می‌کنید، اگر دومین تکرار این عنصر در اندیس x باشد. (یعنی a1=axa_1= a_x) برای هر 1i<x1 \le i \lt x مقدار mim_i ممکن است عوض شود و بقیه تغییری نمی‌کنند چون قبلا در خانه اول a1a_1 وجود داشته و تمام پیشوند‌هایی که از خانه x رد می‌شودند هنوز a1a_1 را دارند. و از طرفی برای هر کدام از آن iها مقدار mim_i مینیمم گرفته می‌شود با a1a_1 چون ممکن است این عنصر اولین کسی باشد که دیگر در بازه نیست.

پیاده سازی الگوریتم با درخت سگمنت یا BST امکان پذیر است.