| اگر تا حالا توی کوئرا سوالی حل نکردی این ویدیو رو ببین! |
|:---:|
| %video.arvan_https://player.arvancloud.ir/index.html?config=https://qvideo.arvanvod.ir/Z7LYW3YQBA/7xQM9V4Vk9/origin_config.json% |
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
در این سوال به شما دو عدد صحیح مثل $a$ و $b$ داده میشود. از شما میخواهیم برنامهای بنویسید که مقدار $a$ و $b$ را دریافت کند و $a + b$ را چاپ کند.
# ورودی
در تنها سطر ورودی، دو عدد صحیح $a$ و $b$ که با یک فاصله از هم جدا شدهاند، داده میشود.
$$1 \leq a, b \leq 100$$
# خروجی
در تنها سطر خروجی، مقدار $a + b$ را چاپ کنید.
# مثالها
## ورودی نمونه ۱
```
3 5
```
## خروجی نمونه ۱
```
8
```
## ورودی نمونه ۲
```
1 1
```
## خروجی نمونه ۲
```
2
```
##نمونه راه حل
```
package main
import "fmt"
func main() {
var sum , n , a int
fmt.Scan(&n)
sum = 0
for i := 0 ; i < n ; i++{
fmt.Scan(&a)
sum = sum + a
}
fmt.Println(sum)
}
```
جمع دو عدد
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
برگزارکنندگان رویداد المپیک فناوری قصد دارند تا برآورد اولیهای از هزینه برگزاری این رویداد داشته باشند.
با توجه به دادههای سالهای گذشته و همچنین تعداد شرکتکنندگان مرحله انتخابی امسال، برای هر حوزه رقابتی تعداد شرکتکنندگان و هزینه بهازای هر نفر برآورد شده است.
از شما خواسته میشود با استفاده از این اطلاعات، **هزینه کلی برگزاری رویداد** را محاسبه کنید.
# ورودی
+ در خط اول عدد صحیح $n$ (تعداد حوزههای رقابتی) داده میشود.
$$0 \le n \le 10^5$$
+ در $n$ خط بعد، در هر خط دو عدد صحیح $s$ و $c$ بهترتیب بیانگر تعداد شرکتکنندگان و هزینه بهازای هر شرکتکننده در آن حوزه داده میشود.
تضمین میشود که هزینه نهایی در محدودهی نوع دادهی **int64** قرار دارد.
# خروجی
یک عدد صحیح که نشاندهندهی **کل هزینه برگزاری رویداد** است، چاپ کنید.
# مثال
## ورودی نمونه ۱
```
1
100 200000
```
## خروجی نمونه ۱
```
20000000
```
توضیح: تنها یک حوزه وجود دارد؛ تعداد شرکتکنندگان ۱۰۰ نفر و هزینه بهازای هر نفر ۲۰۰٬۰۰۰ است. بنابراین هزینه نهایی برابر ۱۰۰ * ۲۰۰۰۰۰ =۲۰٬۰۰۰٬۰۰۰ خواهد بود.
## ورودی نمونه ۲
```
3
100 150000
150 200000
50 300000
```
## خروجی نمونه ۲
```
60000000
```
برآورد هزینه رویداد
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------

# ورودی
در خط اول عدد صحیح $n$ (تعداد حوزهها) داده میشود.
$$0 \le n \le 200$$
سپس برای هر حوزه دو خط داده خواهد شد:
+ خط اول شامل دو عدد صحیح $S$ (امتیاز حوزه) و $P$ (تعداد شرکتکنندگان حوزه) است.
$$0 \le S,P \le 1000$$
+ خط دوم شامل $P$ نام کاربری است که با `,` از هم جدا شدهاند.این نامها به ترتیب رتبه مرتب شدهاند (نام اول رتبه ۱، نام دوم رتبه ۲، و …).
# خروجی
نام کاربری شرکتکنندگان را به ترتیب **امتیاز نهایی (نزولی)** چاپ کنید. هر نام کاربری را در یک خط جداگانه چاپ کنید( به خروجی نمونه دقت کنید.)
+ در صورت وجود چند پاسخ معتبر (مثلاً امتیاز برابر)، هر ترتیب درست قابل قبول است.
# مثال
## ورودی نمونه ۱
```
2
200 3
ali,sara,reza
150 2
sara,omid
```
## خروجی نمونه ۱
```
sara
ali
omid
reza
```
امتیاز در هر حوزه :
حوزه ۱ (S=200, P=3):
+ `ali`: رتبه ۱ → 200
+ `sara`: رتبه 2 → 100
+ `reza`: رتبه 3 → 0
حوزه ۲ (S=150, P=2):
+ `sara`: رتبه ۱ → 150
+ `omid`: رتبه ۲ → 0
امتیاز نهایی:
+ `sara`: 100 + 150 = 250
+ `ali`: 200
+ `omid`: 0
+ `reza`: 0
انتخاب برنده برندهها
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
بعد از انجام برآوردهای اولیه، حالا به سامانهای برای مدیریت رویداد نیاز داریم. این سامانه باید قابلیتهای زیر را پشتیبانی کند:
<details>
<summary> **ایجاد رویداد** </summary>
برای ایجاد رویداد دستور زیر وارد میشود که در آن eventName نام رویداد و costPerPerson هزینه رویداد به ازای هرشرکتکننده است.
```
CREATE eventName costPerPerson
```
در صورتی که نام رویداد تکراری باشد، باید پیام خطا زیر چاپ شود:
```
UNSUCCESSFUL CREATE
```
</details>
<details>
<summary> **حذف رویداد** </summary>
برای حذف رویداد دستور زیر وارد میشود که در آن eventName نام رویداد است.
```
DELETE eventName
```
در صورتی که نام رویداد وجود نداشته باشد، باید پیام خطا زیر چاپ شود:
```
INVALID EVENTNAME
```
</details>
<details>
<summary> **افزودن شرکت کننده به یک رویداد** </summary>
برای افزودن شرکت کننده به یک رویداد دستور زیر وارد میشود که در آن userName نام کابر و eventName نام رویداد مورد است.
```
ADD userName EventName
```
درصورتی که کاربر از قبل به رویداد اضافه شده باشد، باید پیام خطا زیر چاپ شود:
```
USER ALREADY ADDED TO EVENT
```
در صورتی که نام رویداد وجود نداشته باشد، باید پیام خطا زیر چاپ شود:
```
INVALID EVENTNAME
```
</details>
<details>
<summary> **حذف شرکت کننده از یک رویداد** </summary>
برای حذف شرکت کننده از یک رویداد دستور زیر وارد میشود که در آن userName نام کابر و eventName نام رویداد مورد نظر است.
```
REMOVE userName EventName
```
درصورتی که کاربر از قبل در ایونت وجود نداشته، باید پیام خطا چاپ شود:
```
USER NOT FOUND IN EVENT
```
در صورتی که نام رویداد وجود نداشته باشد، باید پیام خطا زیر چاپ شود:
```
INVALID EVENTNAME
```
</details>
<details>
<summary> **محاسبه هزینه رویداد** </summary>
برای محاسبه هزینه رویداد دستور زیر وارد میشود که در آن eventName نام رویداد است. هزینه هر رویداد معادل حاصل ضرب تعداد شرکت کنندگان آن رویداد و هزینه به ازای هر شرکت کننده است.
```
COST eventName
```
در صورتی که نام رویداد وجود نداشته باشد، باید پیام خطا زیر چاپ شود:
```
INVALID EVENTNAME
```
</details>
<details>
<summary> **خروج از سامانه** </summary>
برای اتمام کار سامانه دستور زیر وارد میشود. تضمین میشود در پاین هر مجموعه ای از دستورات این دستور وارد شود.
```
FINISH
```
</details>
# ورودی و خروجی
در هر خط ورودی یکی از دستورات فوق وارد میشود.
تعداد خط های ورودی از $10^5$کمتر خواهد بود.
تضمین میشود در خط آخر دستورات دستور **خروج از سامانه** وارد شود و بعد از آن دستور دیگری وارد نشود.
تضمین میشود که هزینه نهایی در محدودهی نوع دادهی **int64** قرار دارد.
در صورت اجرای موفق پیام زیر و در صورت وجود خطا پیغام خطا مرتبط چاپ میشود ، به استثنا دستور محسابه هزینه که باید **مقدار هزینه** محاسبهشده چاپ شود.
```
SUCCESSFUL
```
# مثال
## ورودی نمونه ۱
```
CREATE olympic 200000
ADD ali olympic
ADD sara olympic
COST olympic
FINISH
```
## خروجی نمونه ۱
```
SUCCESSFUL
SUCCESSFUL
SUCCESSFUL
400000
```
در گام اول یک رویداد با نام olympic و هزینه هر نفر ۲۰۰۰۰۰ ساخته میشود.
در گام های دوم و سوم دو کاربر با موفقیت به رویداد olympic اضافه میشوند.
در گام چهارم هزینه رویداد محاسبه میشود که برابر است با ۲*۲۰۰۰۰۰ =۴۰۰٬۰۰۰ .
## ورودی نمونه ۲
```
CREATE techfest 100000
CREATE techfest 150000
DELETE codecup
ADD reza techfest
ADD reza techfest
REMOVE sara techfest
REMOVE reza codecup
COST codecup
COST techfest
FINISH
```
## خروجی نمونه ۲
```
SUCCESSFUL
UNSUCCESSFUL CREATE
INVALID EVENTNAME
SUCCESSFUL
USER ALREADY ADDED TO EVENT
USER NOT FOUND IN EVENT
INVALID EVENTNAME
INVALID EVENTNAME
100000
```
مدیریت رویداد
+ محدودیت زمان: ۱ ثانیه
+ محدودیت حافظه: ۲۵۶ مگابایت
----------
برگزارکنندگان المپیک هنگام برنامهریزی مسابقات با پرسشی روبهرو شدند:**اختتامیه باید در کدام یک از ساختمانهای پارک علم و فناوری برگزار شود؟**
از آنجا که هر حوزه علاقهمند بود مراسم تا حد ممکن به محل خودش نزدیک باشد، تصمیم گرفتند **مرکزیترین ساختمان پارک** را بهعنوان محل برگزاری انتخاب کنند.
«مرکزیترین ساختمان پارک» به ساختمانی گفته میشود که اگر فاصلهاش را تا تمام ساختمانهای دیگر حساب کنیم، **بیشترین فاصلهی آن (یعنی فاصلهاش تا دورترین ساختمان)** در بین همه ساختمانها **کمترین مقدار** باشد.به بیان ساده، این ساختمان جایی است که حتی دورترین ساختمان هم نسبت به آن تا حد امکان نزدیکتر باشد.
# ورودی
نقشهی پارک به صورت یک گراف وزندار داده میشود.
+ در خط اول، دو عدد صحیح $n$ (تعداد ساختمانها) و $m$ (تعداد راهها) داده میشود.
$$0 \le n \le 500$$
$$0 \le m \le 130000$$
+ در $m$ خط بعد، هر خط شامل سه عدد $u$، $v$ و $c$ است که نشاندهندهی وجود یک راه دوطرفه بین ساختمانهای $u$ و $v$ با وزن $c$ است.
+ تضمین میشود گراف ساختمان ها همبند است و همچنین فاصله دور ترین ساختمان ها از هم در محدوده **int64** قرار دارد.
# خروجی
در تنها یک خط شمارهی **مرکزیترین ساختمان پارک** را چاپ کنید.
ممکن است بیش از یک ساختمان بهعنوان **مرکزیترین ساختمان پارک** شناخته شود. در این صورت، چاپ کردن یکی از آنها بهتنهایی کافی است.
# مثال
## ورودی نمونه ۱
```
4 4
1 2 3
2 3 2
3 4 4
1 4 6
```
## خروجی نمونه ۱
```
3
```
+ نقشه شامل ۴ ساختمان و ۴ راه است.
+ فاصلههای کوتاهترین مسیر از هر ساختمان به بقیه:
| ساختمان | فاصله تا ۱ | فاصله تا ۲ | فاصله تا ۳ | فاصله تا ۴ | بیشترین فاصله |
| ------- | ---------- | ---------- | ---------- | ----------------- | ------------- |
| **1** | 0 | 3 | 5 | 6 | **6** |
| **2** | 3 | 0 | 2 | 6 | **6** |
| **3** | 5 | 2 | 0 | 4 | **5** |
| **4** | 6 | 6 | 4 | 0 | **6** |
+ حالا باید ساختمانی پیدا کنیم که «بیشترین فاصلهاش» کمترین مقدار باشد:
+ برای ساختمان 1 بیشترین فاصله = 6
+ برای ساختمان 2 بیشترین فاصله = 6
+ برای ساختمان 3 بیشترین فاصله = 5
+ برای ساختمان 4 بیشترین فاصله = 6
پس **ساختمان 3** مرکزیترین است.
## ورودی نمونه ۲
```
5 6
1 2 2
2 3 2
3 4 2
4 5 2
1 5 10
2 5 3
```
## خروجی نمونه ۲
```
3
```
محل برگزاری اختتامیه
پس از استخدام در پارک علم و فناوری پردیس، یکی از غولهای تکنولوژی کشور در یک حرکت خلاقانه و در راستای خودکفایی تصمیم گرفته یک پیادهسازی فان از `Docker` با نام `Dockerious` توسعه دهد. این پروژه به عنوان پروژه شما در دوران آزمایشی تعیین شده. در فاز اول شرکتکنندگان باید بخش هستهای و ابتدایی این ابزار را پیادهسازی کنند.
شما باید یک ابزار خط فرمان *(CLI)* ساده بسازید که بتواند دستورات سیستمعامل را (البته از لیست مجاز قرار داده شده در `internal/commands/allowed.go`) در پسزمینه اجرا کرده و وضعیت آنها را ترک کند.
### جزئیات پروژه
پروژه اولیه را از [این لینک](/contest/assignments/84125/download_problem_initial_project/285903/) دانلود کنید. ساختار پروژه به شکل زیر است:
```Shell
├── cmd
│ ├── ps.go # TODO Implement
│ ├── root.go # TODO Implement
│ └── run.go # TODO Implement
├── go.mod
├── go.sum
├── internal
│ ├── commands
│ │ └── allowed.go
│ ├── db
│ │ └── database.go
│ ├── models
│ │ └── process.go
│ ├── monitor
│ │ └── monitor.go
│ └── types
│ └── status.go
├── main.go
```
در این پروژه، شما صرفا باید قسمتهای مشخص شده با `// TODO` را در دایرکتوری `cmd` پیادهسازی کنید. هدف اصلی، پیادهسازی منطق دو دستور اصلی `dockerious run` و `dockerious ps` است.
1. **`internal/commands/allowed.go`**: یک `map` حاوی لیست دستورات مجاز (`echo`, `ls`, `sleep`, `pwd`) را تعریف میکند.
2. **`internal/db/database.go`**: مسئولیت اتصال به پایگاهداده *PostgreSQL* را بر عهده دارد.
3. **`internal/models/process.go`**: مدل *GORM* برای جدول `processes` را تعریف میکند.
4. **`internal/types/status.go`**: وضعیتهای مختلف یک پروسه (`running`, `finished`, `failed`) را به صورت ثابت تعریف میکند.
5. **`internal/monitor/monitor.go`**: یک اینترفیس برای نظارت بر چرخه حیات پروسهها تعریف میکند. شما باید پیادهسازی آن را در `cmd/run.go` انجام دهید.
> ⚠️ نباید ساختار فایلهای داخل `internal` را تغییر دهید — فقط `cmd/*.go` قسمتهایی که `// TODO` دارند باید تکمیل شوند.
### مدل پایگاهداده
ساختار جدول `processes` در پایگاهداده که مدل آن در `models/process.go` تعریف شده، به شرح زیر است:
| فیلد | تایپ | توضیحات |
|-------------|-------------|-----------------------------------------------|
| `ID` | `uint` | کلید اصلی `AUTO_INCREMENT` |
| `PID` | `int` | شناسهی پروسه که سیستمعامل برمیگرداند |
| `Command` | `string` | دستور کامل اجرا شده |
| `Status` | `string` | وضعیت پروسه (`running`، `finished`، `failed`) |
| `CreatedAt` | `time.Time` | زمان ایجاد رکورد |
| `UpdatedAt` | `time.Time` | زمان آخرین بهروزرسانی رکورد |
|
| `DeletedAt` | `time.Time` | زمان حذف رکورد |
### دستورات خط فرمان
شما باید توابع و متدهای خالی مشخصشده با `// TODO` را در فایلهای **`cmd/root.go`**، **`cmd/run.go`** و **`cmd/ps.go`** کامل کنید.
<details class="blue"><summary>فایل `cmd/root.go`</summary>
**توضیح:**
این فایل مسئول راهاندازی ساختار اصلی CLI است. شما باید دستورات فرزند را به دستور ریشه متصل کرده و نقطهی ورود برنامه را تکمیل کنید.
**نیازمندیها:**
+ **`func init()`**: در این تابع، باید دستورات `runCmd` و `psCmd` را به عنوان فرزند به `rootCmd` اضافه کنید.
+ **`func Execute()`**: این تابع که از `main.go` فراخوانی میشود، باید `rootCmd` را اجرا کرده و خطاهای احتمالی را مدیریت کند.
+ **`func GetRootCmdForTest()`**: این تابع در تستها استفاده میشود و شما نباید آن را ویرایش کنید!
</details>
<details class="blue"><summary>فایل `cmd/run.go`</summary>
**توضیح:**
این فایل منطق اصلی اجرای یک پروسه جدید را در خود جای داده است.
**نیازمندیها:**
+ **`struct AsyncProcessMonitor`**: شما باید این `struct` را به گونهای پیادهسازی کنید که اینترفیس `monitor.ProcessMonitor` را ارضا کند.
+ **`func (dpm *AsyncProcessMonitor) MonitorProcess(...)`**: این متد باید یک **گوروتین** اجرا کند. این گوروتین باید منتظر بماند تا پروسهی ورودی (`proc`) تمام شود و سپس وضعیت رکورد متناظر با آن `pid` را در دیتابیس به `types.StatusFinished` تغییر دهد.
+ **`var runCmd = &cobra.Command{...}`**: در تابع `Run` این دستور، باید منطق کامل زیر را پیادهسازی کنید:
1. **بررسی Whitelist**: چک کنید که آیا فرمان ورودی در `commands.AllowedCommands` وجود دارد یا خیر. در صورت عدم وجود، اگر دستور مجاز نباشد، باید خطا را به شکل زیر چاپ کنید و هیچ رکوردی هم در دیتابیس ذخیره نشود:
```shell
[Dockerious] Error: Command '<command>' is not allowed.
```
2. **آرگومانها**: اگر بدون هیچ آرگومانی صدا زده شود، باید خطای پیشفرض (`requires at least 1 arg(s)`) بازگردانده شود.
3. **اجرای پروسه**: با استفاده از `os/exec` و متد `Start()`، پروسه را در پسزمینه اجرا کنید.
4. **ثبت در دیتابیس**: یک رکورد جدید برای پروسه در دیتابیس با وضعیت `types.StatusRunning` ایجاد کنید.
5. چاپ خروجی موفقیت: پس از اجرای موفق، پیام زیر چاپ شود:
```shell
[Dockerious] Started process "<command and args>" with PID: <pid>
```
6. **شروع نظارت**: با استفاده از `monitor.GetProcessMonitor()`، متد `MonitorProcess` را برای پروسهی جدید فراخوانی کنید تا وضعیت آن پس از اتمام، به صورت خودکار آپدیت شود.
</details>
<details class="blue"><summary>فایل `cmd/ps.go`</summary>
**توضیح:**
این دستور برای نمایش لیست پروسههای در حال اجرا و اصلاح وضعیت رکوردهای تاریخگذشته است.
**نیازمندیها:**
+ **`var psCmd = &cobra.Command{...}`**: در تابع `Run` این دستور، باید منطق کامل زیر را پیادهسازی کنید:
1. **واکشی از دیتابیس**: تمام پروسههایی که وضعیت آنها `types.StatusRunning` است را از دیتابیس بخوانید.
2. **منطق Reconciliation**: برای هر پروسه، با استفاده از `os.FindProcess` و ارسال سیگنال `0`، بررسی کنید که آیا واقعاً در سیستمعامل در حال اجراست یا خیر.
3. **آپدیت وضعیت**: اگر پروسهای در سیستمعامل وجود نداشت، وضعیت آن را در دیتابیس با فراخوانی تابع `updateStatusToFinished` بهروز کنید و دیگر در خروجی نمایش داده نشود.
4. **چاپ خروجی**: لیست نهایی پروسههایی که واقعاً در حال اجرا هستند را در قالب یک جدول مرتب چاپ کنید.
+ برای فرمت جدول میتوانید از خط زیر کمک بگیرید:
```go
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.TabIndent)
fmt.Fprintln(w, "ID\tPID\tSTATUS\tCOMMAND")
```
خروجی باید همیشه با هدر زیر شروع شود:
`ID PID STATUS COMMAND `
و در ادامه هر رکورد یک پروسه نمایش داده شود.
+ **`func updateStatusToFinished(...)`**: این تابع کمکی باید یک رکورد پروسه را دریافت کرده و وضعیت آن را در دیتابیس به `types.StatusFinished` تغییر دهد.
</details>
### نکات
+ فایلهای `db.go` و `main.go` از قبل آماده شدهاند و صرفا برای اجرا در محیط لوکال میتوانید آنها را تغییر دهید.
+ تنها فایلهایی که نیاز به ویرایش دارند، فایلهای داخل پوشهی `cmd/` هستند.
### چه چیزی را آپلود کنید
پس از پیادهسازی ویژگیهای خواستهشده، **فقط** دایرکتوریهای `cmd` را فشرده کرده و به صورت یک فایل زیپ ارسال کنید.