راهنمایی سؤالات مسابقهٔ دست‌گرمی الگوریتم کدکاپ ۷ 

1263

راه‌حل‌های سؤالات مسابقهٔ دست‌گرمی الگوریتم کدکاپ ۷ در ادامه توضیح داده شدند. در صورتی که متوجه راه‌حلی نشدید، می‌تونید در بخش نظرات، سؤالات و ابهام‌های خودتون رو مطرح کنید. اگه راه‌حل دیگه‌ای برای سؤالات دارید، خوشحال می‌شیم که راه‌حلتون رو در بخش نظرات با ما و دوستانتون به اشتراک بذارید.

تکرار کدکاپی

با توجه به اینکه مقدار nای که به برنامه‌ی شما داده می‌شود خیلی بزرگ نیست، می‌توان رشته‌ی codecup6codecup6... را تا حداقل ۱۰۰ کاراکتر در رشته‌ای مثل s ذخیره کرده و با دریافت n مقدار s[n] را چاپ کرد.

راه‌حل به زبان سی‌پلاس‌پلاس:

#include <iostream>

using namespace std;

int main()
{
	string s = "";
	for (int i = 0; i < 13; i++)
		s += "codecup6";

	int n;
	cin >> n;
	cout << s[n - 1] << endl;

	return 0;
}

راه‌حل به زبان پایتون:

s = "codecup6" * 13
n = int(input())
print(s[n - 1])

دَنگ و دُنگ

مسئله برای هر تست را جدا حل می‌کنیم. مجموع هزینه‌ای که باید همه‌ی افراد بپردازند برابر است با:

S + (n - 1)a

پس اگر بخواهیم همه به اندازه‌ی برابر در هزینه‌ها شریک باشند، هرکس باید:

\frac{S + (n - 1)a}{n}

از حسابش کم شود. پس همه (به جز مادرخرج) باید:

\frac{S + (n - 1)a}{n} - a = \frac{S - a}{n}

بنابراین در صورتی که S - a بر n بخش‌پذیر و یا مثبت نباشد، باید 1- را چاپ کرده و در غیر این‌صورت \frac{S - a}{n} را چاپ می‌کنیم.

راه‌حل به زبان سی‌پلاس‌پلاس:

#include <iostream>

using namespace std;

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, S, a;
		cin >> n >> S >> a;

		if (S - a <= 0 || (S - a) % n != 0)
			cout << "-1\n";
		else
			cout << (S - a) / n << "\n";
	}
	
	return 0;
}

راه‌حل به زبان پایتون:

t = int(input())
for i in range(t):
	n, s, a = map(int, input().split())
	if s - a <= 0 or (s - a) % n != 0:
		print(-1)
	else:
		print((s - a) // n)

هگزانوردی

می‌خواهیم رشته‌ی داده‌شده را تغییر دهیم تا به مسیری با طول بهینه برسیم. توجه کنید که ترتیب قرار گرفتن کاراکترها در رشته‌ی داده‌شده، تغییری در پاسخ مسئله ایجاد نمی‌کند. (چرا؟)

پس می‌توانیم یک مسیر را با ۶ عدد صحیح و نامنفی cnt_A، cnt_B، cnt_C، cnt_D، cnt_E و cnt_F نشان دهیم.

می‌توان با توجه به جهت بردارها گفت:

  • حرکت A و D برعکس یکدیگرند.
  • حرکت B و E برعکس یکدیگرند.
  • حرکت C و F برعکس یکدیگرند.

پس می‌توان فرض کرد که از هرکدام از این ۳ دسته، حداکثر یک حرکت وجود دارد. چون در غیر این صورت از هر دو نوع حرکت یک واحد کم می‌کنیم.

همچنین با توجه به قانون جمع بردارها می‌توان گفت:

  • دو حرکت A و C معادل یک حرکت B است.
  • دو حرکت B و D معادل یک حرکت C است.
  • دو حرکت C و E معادل یک حرکت D است.
  • دو حرکت D و F معادل یک حرکت E است.
  • دو حرکت E و A معادل یک حرکت F است.
  • دو حرکت F و B معادل یک حرکت A است.

پس می‌توان فرض کرد از ۶ حرکت موجود، حداکثر ۲ نوع حرکت می‌توان داشت (چرا؟) و پاسخ مسئله برابر جمع این دو عدد است.

راه‌حل به زبان سی‌پلاس‌پلاس:

#include <iostream>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(0);

    int t;
    cin >> t;
    while (t--)
    {
        string s;
        cin >> s;

        int cnt[6] = {0, 0, 0, 0, 0, 0};
        for (int i = 0;  i < (int)s.size(); i++)
            cnt[s[i] - 'A']++;

        for (int i = 0; i < 3; i++)
        {
            int m = min(cnt[i], cnt[i + 3]);
            cnt[i] -= m;
            cnt[i + 3] -= m;
        }

        for (int i = 0; i < 6; i++)
        {
            int m = min(cnt[i], cnt[(i + 2) % 6]);
            cnt[i] -= m;
            cnt[(i + 2) % 6] -= m;
            cnt[(i + 1) % 6] += m;

            int idx = (i + 1) % 6;
            
            m = min(cnt[idx], cnt[(idx + 3) % 6]);
            cnt[idx] -= m;
            cnt[(idx + 3) % 6] -= m;
        }

        int ans = 0;
        for (int i = 0; i < 6; i++)
            ans += cnt[i];

        cout << ans << '\n';
    }
    return 0;
}

راه‌حل به زبان پایتون:

t = int(input())
for r in range(t):
    s = input()
    cnt = [0, 0, 0, 0, 0, 0]
    for c in s:
        cnt[ord(c) - ord('A')] += 1

    for i in range(3):
        m = min(cnt[i], cnt[i + 3])
        cnt[i] -= m
        cnt[i + 3] -= m

    for i in range(6):
        m = min(cnt[i], cnt[(i + 2) % 6])
        cnt[i] -= m
        cnt[(i + 2) % 6] -= m
        cnt[(i + 1) % 6] += m

        idx = (i + 1) % 6
        
        m = min(cnt[idx], cnt[(idx + 3) % 6])
        cnt[idx] -= m
        cnt[(idx + 3) % 6] -= m

    print(sum(cnt))

دنباله گمشده

می‌توان ثابت کرد اگر پاسخی برای مسئله موجود باشد می‌تواند یک پیشوند از دنباله‌ی b باشد. (چرا؟)

حال می‌خواهیم برای هر پیشوند از b بررسی کنیم که آیا می‌تواند یک پاسخ برای مسئله باشد یا نه. برای این کار نیاز داریم بررسی کنیم که آیا دو زیردنباله‌ی به‌هم‌چسبیده از b با هم برابر هستند یا نه. که برای مقایسه‌ی چنین چیزی می‌توانیم از الگوریتم‌های درهم‌سازی یا hashing یا Z-Algorithm استفاده کنیم.

توجه کنید که اگر همه‌ی زیررشته‌ها را بررسی کنیم، مرتبه زمانی از O(m.log(m)) خواهد شد. چون برای مقایسه کردن پیشوند به طول k باید \lceil\frac{m}{k}\rceil زیردنباله‌ی متوالی از b را با هم مقایسه کنیم.

پس اگر فرض کنیم هر مقایسه با استفاده از درهم‌سازی از O(1) انجام می‌شود، مرتبه‌ی زمانی کل راه‌حل برابر است با:

\sum_{k=1}^{m} \lceil\frac{m}{k}\rceil - 1 \leq \sum_{k=1}^{m}\frac{m}{k} = m\sum_{k=1}^{m}\frac{1}{k} = m.H(m) \in O(m.log(m))

راه‌حل به زبان سی‌پلاس‌پلاس:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6;
int z[maxn], b[maxn];

void solve() 
{
    int m;
    cin >> m;
    for (int i = 0; i < m; i++)
        cin >> b[i];

    int L = 0, R = 0;
    for (int i = 1; i < m; i++) 
    {
        if (i > R) 
        {
            L = R = i;
            while (R < m && b[R - L] == b[R]) 
                R++;
            z[i] = R - L; 
            R--;
        } 
        else 
        {
            int k = i - L;
            if (z[k] < R - i + 1) 
                z[i] = z[k];
            else 
            {
                L = i;
                while (R < m && b[R - L] == b[R]) 
                    R++;
                z[i] = R - L; 
                R--;
            }
        }
    }

    for (int n = 1; n <= m; n++) 
    {
        bool okay = true;
        for (int i = n; i + n <= m; i += n)
            if (z[i] < n) 
            {
                okay = false;
                break;
            }

        if (m % n != 0 && z[(m / n) * n] < (m % n))
            okay = false;

        if (okay) 
        {
            cout << n << '\n';
            for (int i = 0; i < n; i++)
                cout << b[i] << ' ';
            cout << '\n';
            return;
        }
    }
}

int main() 
{
    ios_base::sync_with_stdio(false); cin.tie(0);

    int tc;
    cin >> tc;
    while (tc--) 
        solve();

    return 0;
}

راه‌حل به زبان پایتون:

t = int(input())
for i in range(t):
    m = int(input())
    a = list(map(int, input().split()))
    base = 313
    mod = [
        int(1e9 + 7),
        int(1e9 + 9),
    ]
    h = [
        [0] * (m + 1), [0] * (m + 1)
    ]
    p = [
        [1] * (m + 1), [1] * (m + 1)
    ]
    for j in range(m):
        p[0][j + 1] = (p[0][j] * base) % mod[0]
        p[1][j + 1] = (p[1][j] * base) % mod[1]
    for j in range(m):
        h[0][j + 1] = (h[0][j] * base + a[j]) % mod[0]
        h[1][j + 1] = (h[1][j] * base + a[j]) % mod[1]
    for j in range(1, m + 1):
        if h[0][m - j] == ((h[0][m] - p[0][m-j] * h[0][j]) % mod[0] + mod[0]) % mod[0]:
            if h[1][m - j] == ((h[1][m] - p[1][m-j] * h[1][j]) % mod[1] + mod[1]) % mod[1]:
                print(j)
                for k in range(j):
                    print(a[k], end=' ')
                print()
                break
آموزش برنامه نویسی با کوئرا کالج
امین انوری سرور

اشتراک در
اطلاع از
guest

10 دیدگاه‌
قدیمی‌ترین
تازه‌ترین بیشترین واکنش
بازخورد (Feedback) های اینلاین
View all comments
Kasra
Kasra
2 سال قبل

سلام شبتون بخیر برای سوال ۷ چه کدی میتوان با پایتون نوشت ؟
ممتون

Kasra
Kasra
2 سال قبل
پاسخ به  Kasra

سوال آخر

محمد
محمد
2 سال قبل

سلام.
برای سوال “تکرار کدکاپی” فکر میکنم این جواب مناسبتر باشه:

<?php
$loc=(int)readline();
$str=['c', 'o', 'd', 'e', 'c', 'u', 'p', '6'];
if($loc<=8){
    echo $str[$loc-1];
}else if($loc>8 && $loc<=100){
    echo $str[(($loc-($loc%8))/8)-1];
}else{
    exit("");
}
کیمیا
کیمیا
2 سال قبل

ببخشید چرا راهنمای سوالات مسابقات دستگرمی دیتاساینس منتشر نشده؟ فقط جاوا و الگوریتم و Go هست؟

کوئرا بلاگ
ادمین
2 سال قبل
پاسخ به  کیمیا

سلام دوست عزیز

سعی می‌کنیم منتشر کنیم

ریحانه
ریحانه
2 سال قبل

سلام من فط تونستم رو دو سوال فکرکنم مشکلی پیش اومد نتونستم اصلا کدبزنم…
اما سوال اول راه حلی که بنظرم رسید ، از باقیمانده تقسیم صحیح عدد ورودی بر ۸ ، میشه اندیس کاراکتر متناظر رو با ذخیره فقط ۸کاراکتر codecup6 تو یه لیست یا استرینگ پیداکرد

این مدل حواب اوکیه؟

آخرین ویرایش2 سال قبل توسط ریحانه
نوروزی
نوروزی
2 سال قبل

سلام
پاسخ سوالات مسابقات اصلی کی در وبلاگ قرار میگیره؟ قبلا روال اینطور بود که خیلی سریع، روز بعد از مسابقات، پاسخ ها قرار میگیرفتند…

کوئرا بلاگ
ادمین
2 سال قبل
پاسخ به  نوروزی

سلام دوست عزیز

به‌زودی پاسخ سؤالات تمام مسیرهای مسابقه به جز دیتاساینس منتشر خواهد شد