Matistjati
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Öar En huvudinsikt i problemet är att man snabbt kan räkna ut hur många deltagare som försvinner på en viss ö om man håller koll på hur många som försvinner på de två senaste. I Python kan det vara ett tillfälle att använda följande syntax för att tilldela flera variabler samtidigt: ```python last_island, this_island = this_island, last_island + this_island ``` Summera sedan antalet deltagare som försvann på varje ö och stanna när det talet är större eller lika med det totala antalet deltagare på IOI. I övrigt är det bara att se till att man har korrekta startvärden och hanterar de väldigt små fallen där bara typ en deltagare försvinner. # Tebryggning För den första testgruppen finns det bara en sorts te, vilket innebär att antalet kannor är antalet deltagare delat på 10 avrundat uppåt. Ett sätt att räkna ut detta i python utan att använda flyttalsdivision och importera en avrunda-uppåt-funktion är följande: ```python antal_kannor = (kannstorlek + antal_personer - 1) // kannstorlek ``` Försök gärna förstå ovanstående om du inte sett det förr! (Notera att ```//``` i Python är heltalsdivision, alltså dela och avrunda neråt till närmaste heltal.) För det generella fallet är det optimalt att koka fulla kannor te så långt det går innan man tvingas börja göra delvis fyllda kannor. Om det går att få ut tillräckligt många fulla kannor för att servera alla blir lösningen som ovan. Annars kan man börja med att servera te till alla som kan från de fulla kannorna. Sen får man ta en lista med hur mycket mer te man kan få ut ur varje tepåse, sortera den, och servera dem en i taget tills alla är nöjda. Ett trevligt sätt att implementera detta är med priority queue/max heap, men detta krävs självklart inte. # Zoo Det här är ett problem där det kan vara värt att se vilka testgrupper som finns och anpassa sin lösning till dem om man inte kommer på den fulla lösningen direkt. ### För den första testgruppen finns det en matematisk formel: Eftersom man kan välja fritt bland alla $k$ djur i första buren och fritt bland alla $k-1$ djur som inte finns i förra buren i alla $n-1$ burar efter det finns det $k \cdot (k-1)^{n-1}$ sätt att placera djuren i den här testgruppen. ### I den andra testgruppen är det inget särskilt som man ska anpassa sig till, men antalet djurarter och burar kan inte vara lika stort som i det generella fallet. Det håller sig så pass litet att det går att göra en brute-force-lösning där man helt enkelt går igenom och räknar alla möjligheter. Denna lösning är smidigast att göra rekursivt, även om det nog är möjligt med en massa nästlade loopar och if-satser. En sån här lösning kommer ta tid proportionellt mot antalet sätt att placera djuren, alltså är tidskomplexiteten $O(k \cdot (k-1)^{n-1})$ enligt uttrycket från testgrupp 1. ### Den tredje testgruppen är lite mer matematiskt komplicerad men går att lösa med en kombination av kombinatorik och programmering. Till exempel genom att först hitta alla sätt att välja vilka burar som ska innehålla ett bråkigt djur, räkna hur många sätt det finns att placera övriga djur runt de bråkiga djuren med hjälp av formeln i testgrupp ett, ta det gånger antalet sätt att fördela bråkiga djurarter i burarna för bråkiga djur, och ta summan av den produkten för alla sätt att välja bråkiga burar. Det är lite knepigare att räkna på tidskomplexitet här, men det går att se att det enda som tar betydande tid är att gå igenom alla sätt att välja vilka burar som ska ha bråkiga djur, och att det finns mindre än $15 \cdot 13 \cdot 11 \cdot 9 \cdot 7 = 135135$ sätt att göra det på. Detta gör att en Python-lösning borde kunna gå igenom med marginal. ### För en full lösning krävs dynamisk programmering, att hålla koll på och återanvända tidigare uträknade saker på ett smart sätt. I det här fallet går det att göra genom att hålla koll på antalet sätt att fördela djur i de första $a$ burarna på ett sådant sätt att den sista av dem innehåller djur $b$. Ett exempel på resultatet av sådana uträkningar finns nedan, där man till exempel kan se att det finns nio sätt att fylla alla fyra burar på ett sådant sätt att det sista djuret är E, att det inte finns något sätt att fylla två burar så att det andra är B, och att svaret i det här fallet (summan av sista kolumnen) är 18. För att fylla i tabellen börjar man med att fylla första kolumnen med ettor (fundera gärna på varför?), sedan fylla i varje kolumn efter det med hjälp av kolumnen innan. Till exempel står det en nia i ruta 4/E eftersom E kan vara intill A, C eller D och summan av deras rutor i kolumnen innan är $3+3+3=9$. Om man räknar ut vilka djur som får vara intill vilka i förväg tar det alltså upp till $K \leq 10$ operationer att fylla i var och en av de $N \cdot K \leq 15 \cdot 10$ rutorna, vilket ger en tidskomplexitet på $O(N \cdot K^2)$ vilket är tillräckligt snabbt med god marginal ($N \cdot K^2 \leq 15 \cdot 10^2 < 10^6$). ``` 4 5 2 BE BADC ``` |$b$ \\ $a$|1|2|3|4($=n$)| |----------|-|-|-|-------| |A |1|1|3|3 | |B |1|0|0|0 | |C |1|1|3|3 | |D |1|1|3|3 | |E |1|3|3|9 | # Planet X Exakt vilken information får vi från kända rutor? Vi tar ett exempel: ruta $K$ är känd och ruta $O$ är okänd. Låt dist($K$, $O$)=kortaste vägen mellan $K$ och $O$. I rutnät är avstånd så-kallat manhattanavstånd, vilket kan beräknas med dist($K$, $O$)=$|K_x-O_x|+|K_y-O_y|$. Varje gång vi tar ett steg från ruta $K$ kommer höjden att förändras med $\pm$ 1. Om ruta $K$ har höjd $h$ och $d$=dist($K$,$O$), så betyder det att höjden av $O$ är inom $[h-d, h+d]$. Detta känns rätt i fallet om vi går kortaste vägen från $K \rightarrow O$, men kan vi inte ta en längre väg och få ett större intervall? Nej! Varje kortaste väg ger oss info som är "optimal"- om vi använder informationen från en väg som inte är kortaste, så kan denna motsäga en kortaste väg, och alla vägars info måste respekteras. Därför duger det att bara betrakta kortaste vägar. Vi försöker nu fylla i de okända rutorna. Låt oss för varje okänd ruta $O$ beräkna intervallet som alla andra kända rutor ger. Vi har nu ett flertal intervall för värdet på $O$. Alla höjder $0 \leq h \leq 9$ som ligger innanför alla intervall är en möjlig höjd för $O$. Om det finns exakt ett möjligt $h$ har vi bestämt höjden för den rutan. Om det finns mer än en är det omöjligt att bestämma höjden entydigt. Blir något i stilen med $O(10N^2M^2)$, vilket är snabbt nog eftersom $N$ och $M$ är jättesmå. # Planetbacke Detta problemet är välkänt som "longest path". I allmänhet är det svårt att lösa snabbare än $O(2^NN^2)$. Vi vet därmed att en vanlig algoritm för longest path är för långsam. Då måste vi leta efter en särskild begräsning som gör det lösbart. I detta problemet är begränsningen som gör det lösbart att "Det finns aldrig fler än $7$ rutor i rutnätet som har samma höjd". Detta gör att en DP kör snabbt nog. Mer exakt så behöver vi inte längre hålla koll på *alla* möjliga rutor vi kan ha besökt, utan bara de med samma höjd som rutan vi befinner oss på. Mer exakt håller vi koll på: - x - y - Om vi vet x och y, så vet vi höjden av rutan vi befinner oss på. Då räcker det att hålla koll på vilka av dom upp till 7 rutorna av samma höjd som vi har besökt. Så, $$\text{DP[x][y][vis]=max längd}$$ Här är en implementation. Den använder ganska många trick. Vi representerar vilka rutor vi besökt (vis) som ett binärt tal. Om vi har $N$ möjliga besökta rutor finns det $2^N$ möjliga delmängder av besökta rutor. Vanligtvis hade vi velat representera detta med ett tal i intervallet $[0, 2^N-1]$. I detta fallet är vi lata: vi använder en dictionary och har ett tal mellan 0 och $2^{NM-1}$. Vi vet dock att det inte kan finnas mer än $2^7$ möjliga värden på $vis$ för ett givet par $(x,y)$. Det kanske även ser långsamt ut när vi anropar best många gånger i botten. Det går fortfarande snabbt eftersom DP:n gör att varje tillstånd kan besökas som mest en gång. Eftersom det finns $NM \cdot 2^7$ kör på programmet i $O(2^7NM)$. ```python n,m=[int(i) for i in input().split()] # Change '1' to 1 grid = [[ord(c)-ord('0') for c in input()] for i in range(n)] memo = {} dirs = ((0,1),(1,0),(0,-1),(-1,0),(1,1),(-1,1),(1,-1),(-1,-1)) def best(r, c, vis): if (r,c,vis) in memo: return memo[(r,c,vis)] h = grid[r][c] ret = 0 for dir in dirs: nr = r + dir[0] nc = c + dir[1] # We can't go outside of grid or to a higher cell if nr < 0 or nc < 0 or nr >= n or nc >= m or grid[nr][nc]>h: continue # Transform 2D coordinate into 1D coordinate ind = nr*m+nc # If we remain at same height if grid[nr][nc]==h: if vis & (1<<ind): # If already visited, skip continue newvis = vis | (1<<ind) # Otherwise, add that it is visited else: newvis = 1<<ind # If new height, remove old visited ret = max(ret, 1+best(nr,nc,newvis)) memo[(r,c,vis)] = ret return ret ans = 0 # Try every starting position # O(NM2^7) amortized for i in range(n): for j in range(m): ans = max(ans, best(i,j,1<<(i*m+j))) print(ans+1) ``` # Cykeltävling Problemet känns väldigt komplext. För att göra det mer angripbart behövs lite insikter. Låt R[i]=springshastigheten av person i, och C[i]=cykelhastigheten av person i. ### Insikt 1: I en optimal lösning hoppar varje person på cykeln och sedan av som mest en gång. Intuitivt beror detta på att cykelbyten är ineffektiva, eftersom det leder till att man behöver vänta mer. ### Insikt 2: Som en följd av insikt 1, så kommer varje person att vilja springa ett visst tag och cykla ett visst tag i en optimal lösning. ### Insikt 3: Vi kan binärsöka över svaret. Vi kan föreställa oss att varje person börjar med en att springa, vilekt tar en viss tid. Vi kan sedan skära ner tider genom att låta de cykla istället, och vi vill minimera den största tiden. Alltså vill vi minimera den största, något som är klassiskt binärsökbart. Hur hjälper binärsökning oss? Låt säga att vi vill kolla om svaret är $\leq mid$. Vi får en klassificering av 3 sorters personer: 1. De som hinner springa i mål. Dessa ignorerar vi 2. De som inte hinner springa i mål, och har C[i] $\leq$ R[i]. För dessa är det omöjligt att hinna i mål på $mid$ sekunder, så vi vet direkt att det inte går. 3. De som inte hinner springa i mål, och har C[i] $>$ R[i]. Vi kan nu använda matte för att beräkna hur mycket de behöver använda cykeln. Det är nu det blir knivigt. Vad händer om någon springar springer förbi den som cyklar? Då behöver personen stanna och vänta, vilket känns väldigt ineffektivt. (Vi kommer att prata om att folk behöver springa ikapp cykeln senare). Vi kan undvika detta med följande schema: - Personen som cyklar snabbast börjar med cykeln. Då kan ingen springa ikapp cykeln. Varför? Låt oss anta att personen som börjar cykla är person nr $1$ och personen som springar förbi är person nr $2$. För att springa förbi måste $R[2] > C[1]$ hålla. Eftersom person nr $2$ är i tredje gruppen (snabbare att cykla än att springa), så håller $C[2] \geq R[2]$. Men då håller också $C[2] > C[1]$, vilket motsäger antagandet att snabbaste cyklisten börjar cykla. - När person nr 1 är färdig med cykeln kan den lämna den. Vi kan nu ignorera person nr 1, den har cyklat färdigt. Första personen att springa fram till cykeln kommer också att vara den snabbaste cyklisten av kvarvarande i laget (kan finnas flera som är lika snabba, spelar ingen roll då). Ingen har då en chans att springa förbi. Detta fortsätter. Då är det enda som är kvar att beräkna hur mycket varje person behöver använda cykeln. Det är frestande att räkna ut detta i sekunder. Tyvärr kommer detta ge fel svar; det räknar inte in att folk kommer behöva springa ikapp cykeln. Istället kommer beräkningen att anta att person 1 använder x sekunder, direkt efter byts det till person 2 osv., vilket uppenbarligen inte stämmer. Detta går att fixa nu när vi vet den optimala ordningen, men är onödigt pilligt. För att lösa detta kan vi istället beräkna hur långt varje person behöver cykla. Varför fixar det problemet? Innan var det problematiska att vi inte nödvändigtvis kan göra direkta byten inom tidsskalan, utan det finns stunder när personer springer ikapp cykeln. Inom avståndsskalan behöver vi däremot inte oroa oss om det längre; vi har redan räknat in både tiden varje person springer respektive cyklar. Vi kan däremot få lite problem även här; ibland säger vår lösning att vi behöver cykla en total längd längre än $l$. Vi använder detta för att avgöra om ett visst $mid$ funkar eller inte. ```python n, l = [int(i) for i in input().split()] run = [0] * n bike = [0] * n for i in range(n): run[i], bike[i] = [int(i) for i in input().split()] lo = 0 hi = l+1 # När vi binärsöker över flyttal är det frestande att göra # while hi-lo>1e-5 # Gör inte detta! Det kan hamna i en oändlig loop pga flyttals-avrundningar # TRO MIG, GÖR ALDRIG DET for _ in range(100): mid = (lo+hi)/2 total_biking_length = 0 for i in range(n): # We can run to goal if run[i] * mid >= l: continue # Completely impossible if bike[i] <= run[i]: bike_length += 100000000 break distance_decrease_needed = l - run[i] * mid # How much distance must we save speed_increase = bike[i] - run[i] # How much faster is biking over running seconds_biking = distance_decrease_needed / speed_increase length_biked = seconds_biking * bike[i] total_biking_length += length_biked if bike_length <= l: hi = mid else: lo = mid print(lo) ```

Import from clipboard

Paste your webpage below. It will be converted to Markdown.

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully