이번에는 Round 1 에디토리얼입니다. 그래프가 없으면 나름 경쟁력이 있는 나나 되겠습니다...
1650명 중에서 750명을 추리는 대회였습니다.
Easy(250pt, SequenceSums)
R1다운 상큼한 문제입니다; 길이 L 이상 100 이하의, 1씩만 증가하는 0 이상의 정수들의 수열의 합이 N이 되도록 하는 최소의 길이의 수열을 찾는 문제입니다.
그냥 길이 L부터 100까지 돌면서, 각 길이마다 이 조건을 만족하는 수열이 있나 체크하면 됩니다. 시작 수를 a라고 하면, (a + (a+L-1)) * L / 2 = N이 되어야 하니, 2a+L-1 = 2N / L 이 되어야 하고, 2a = (2N/L+1-L)이 되어야겠죠. 2N이 L로 나누어 떨어져야 하고, 이 결과로 나온 2a가 0 이상의 짝수여야 하겠습니다. 그대로 구현하면 됩니다.
Medium(500pt, KthProbableElement)
문제가 간단하니 같이 번역을 해봅시다.
M integers are randomly independently chosen from the interval lowerBound...upperBound, inclusive. Return the probability that the K-th smallest element of the generated set is equal to N. K=1 refers to the smallest element, K=2 refers to the second smallest element, and so on.
M개의 정수를 lowerBound 이상 upperBound 이하의 정수들 중에서 랜덤하게 독립적으로 고르자. 이 수들 중 K번째로 작은 수가 N이 될 확률을 리턴해라. K=1이면 가장 작은 원소, K=2면 두번째로 작은 원소, 등등을 뜻한다.
제 경우에는 처음에는 조합론적으로 시도했는데, 생각보다 수식을 만들기가 쉽지 않았습니다. 결국 Dynamic Programming 방법으로 전환했습니다.
아래 코드에서 prob1[a][b] = a개를 골랐을 때, N 이하의 수가 정확히 b개 골라질 확률입니다.
prob2[a][b] = a개를 골랐을 때, N-1 이하의 수가 정확히 b개 골라질 확률입니다.
prob1[a][b~a] 를 모두 합하면, a개를 골랐을 때, N 이하의 수가 b개 이상 골라질 확률이 됩니다. 다시 말하면, b번째로 작은 수가 N 이하인 확률이 됩니다.
prob2[a][b~a] 를 모두 합하면, a개를 골랐을 때, N-1 이하의 수가 b개 이상 골라질 확률이 됩니다. 다시 말하면, b번째로 작은 수가 N-1 이하인 확률이 됩니다.
결국 prob1[a][b~a] 에서 prob[a][b~a]를 빼면, b번째로 작은 수가 N인 확률이 나옵니다.
Hard(900pt, Unicorn)
이 문제는 경우의 수를 세는 아주 전형적인 문제로, DP로 해결할 수 있습니다. 즉 cnt[a][b][c] = 단어의 a번째 글자까지 체크했고, 마지막 글자의 위치가 (b, c)일 때의 경우의 수 라고 하고요, cnt[a-1][...][...]에서 적절히 cnt[a][...][...] 를 구하는 식으로 해서 마지막에 cnt[단어사이즈-1][b][c] 를 모두 더한 수가 답이 됩니다.
한 가지 문제는, cnt[a][b][c]를 구할 때, cnt[a-1][...][...]들을 더해야 하는데, 유니콘이 한 스텝에 움직일 수 있는 (2+, 3+), (3+, 2+)의 좌표들을 모두 고려하면, 판의 대부분의 칸들에 대해서 저 값을 더해야 한다는 것입니다. 그림을 그려보면, 다음 위치에서만 유니콘이 올 수가 없습니다 - x 좌표 차이가 1 이하이거나, y 좌표 차이가 1 이하이거나, x 좌표 차이와 y 좌표 차이가 모두 2인 경우.
즉 (모든 위치에 대해서 합을 더한 값) - (x좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) - (y좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) + (x좌표 차이가 -1~1이고 y좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) - (x좌표 차이가 2이고 y좌표 차이가 2인 위치에 대해서 합을 더한 값) 이 cnt[a][b][c] 가 됩니다. 여기서 '모든 위치에 대해서 합을 더한 값', 'x좌표가 i인 모든 위치에 대해서 합을 더한 값', 'y좌표가 j인 모든 위치에 대해서 합을 더한 값' 을 각 a에 대해서 한번만 계산하면, 이후의 계산을 O(1)로 할 수 있음을 알 수 있습니다.
실제 코드 구현도 이렇게 되어 있으니 보시면 쉽게 이해가 되실 것이라 생각합니다.
#include <vector>#include <string>#include <queue>#include <map>#include <math.h>#include <cmath>#include <algorithm>usingnamespacestd;constintmmod=1000000007;longlongcnt[300][300]={0};longlongnext[300][300]={0};charchessboard[300][300]={0};classUnicorn{public:intcountWays(intR,intC,intL,intseed,stringword){intpx[13]={-2,2,-2,2,-1,0,1,-1,0,1,-1,0,1};intpy[13]={-2,-2,2,2,-1,-1,-1,0,0,0,1,1,1};intmult[13]={-1,-1,-1,-1,1,1,1,1,1,1,1,1,1};{intx=seed;intd=(65535/L)+1;for(intr=0;r<R;r++)for(intc=0;c<C;c++){x=(x*25173+13849)%65536;chessboard[r][c]=65+x/d;}}for(inti=0;i<R;i++)for(intj=0;j<C;j++)if(chessboard[i][j]==word[0])cnt[i][j]=1;for(inti=1;i<word.size();i++){chartarget=word[i];longlongrow_sum[300]={0};longlongcolumn_sum[300]={0};longlongtotal=0;/* for (int i=0; i<R; i++) for (int j=0; j<C; j++) printf("%lld ", cnt[i][j]); printf("n");*/for(inti=0;i<R;i++)for(intj=0;j<C;j++){row_sum[i]=(row_sum[i]+cnt[i][j])%mmod;column_sum[j]=(column_sum[j]+cnt[i][j])%mmod;total=(total+cnt[i][j])%mmod;}for(inti=0;i<R;i++)for(intj=0;j<C;j++){next[i][j]=0;if(target==chessboard[i][j]){next[i][j]=total;if(i>0)next[i][j]-=row_sum[i-1];next[i][j]-=row_sum[i];if(i<R-1)next[i][j]-=row_sum[i+1];if(j>0)next[i][j]-=column_sum[j-1];next[i][j]-=column_sum[j];if(j<C-1)next[i][j]-=column_sum[j+1];for(intk=0;k<13;k++)if(i+py[k]>=0&&i+py[k]<R&&j+px[k]>=0&&j+px[k]<C)next[i][j]+=mult[k]*cnt[i+py[k]][j+px[k]];while(next[i][j]<0)next[i][j]+=mmod;next[i][j]%=mmod;}}for(inti=0;i<R;i++)for(intj=0;j<C;j++)cnt[i][j]=next[i][j];}/* for (int i=0; i<R; i++) for (int j=0; j<C; j++) printf("%lld ", cnt[i][j]); printf("n");*/longlongres=0;for(inti=0;i<R;i++)for(intj=0;j<C;j++)res=(res+cnt[i][j])%mmod;returnres;};};
일루
이번에는 Round 1 에디토리얼입니다. 그래프가 없으면 나름 경쟁력이 있는 나나 되겠습니다...
1650명 중에서 750명을 추리는 대회였습니다.
Easy(250pt, SequenceSums)
R1다운 상큼한 문제입니다; 길이 L 이상 100 이하의, 1씩만 증가하는 0 이상의 정수들의 수열의 합이 N이 되도록 하는 최소의 길이의 수열을 찾는 문제입니다.
그냥 길이 L부터 100까지 돌면서, 각 길이마다 이 조건을 만족하는 수열이 있나 체크하면 됩니다. 시작 수를 a라고 하면, (a + (a+L-1)) * L / 2 = N이 되어야 하니, 2a+L-1 = 2N / L 이 되어야 하고, 2a = (2N/L+1-L)이 되어야겠죠. 2N이 L로 나누어 떨어져야 하고, 이 결과로 나온 2a가 0 이상의 짝수여야 하겠습니다. 그대로 구현하면 됩니다.
Medium(500pt, KthProbableElement)
문제가 간단하니 같이 번역을 해봅시다.
M integers are randomly independently chosen from the interval lowerBound...upperBound, inclusive. Return the probability that the K-th smallest element of the generated set is equal to N. K=1 refers to the smallest element, K=2 refers to the second smallest element, and so on.
M개의 정수를 lowerBound 이상 upperBound 이하의 정수들 중에서 랜덤하게 독립적으로 고르자. 이 수들 중 K번째로 작은 수가 N이 될 확률을 리턴해라. K=1이면 가장 작은 원소, K=2면 두번째로 작은 원소, 등등을 뜻한다.
제 경우에는 처음에는 조합론적으로 시도했는데, 생각보다 수식을 만들기가 쉽지 않았습니다. 결국 Dynamic Programming 방법으로 전환했습니다.
아래 코드에서 prob1[a][b] = a개를 골랐을 때, N 이하의 수가 정확히 b개 골라질 확률입니다.
prob2[a][b] = a개를 골랐을 때, N-1 이하의 수가 정확히 b개 골라질 확률입니다.
prob1[a][b~a] 를 모두 합하면, a개를 골랐을 때, N 이하의 수가 b개 이상 골라질 확률이 됩니다. 다시 말하면, b번째로 작은 수가 N 이하인 확률이 됩니다.
prob2[a][b~a] 를 모두 합하면, a개를 골랐을 때, N-1 이하의 수가 b개 이상 골라질 확률이 됩니다. 다시 말하면, b번째로 작은 수가 N-1 이하인 확률이 됩니다.
결국 prob1[a][b~a] 에서 prob[a][b~a]를 빼면, b번째로 작은 수가 N인 확률이 나옵니다.
Hard(900pt, Unicorn)
이 문제는 경우의 수를 세는 아주 전형적인 문제로, DP로 해결할 수 있습니다. 즉 cnt[a][b][c] = 단어의 a번째 글자까지 체크했고, 마지막 글자의 위치가 (b, c)일 때의 경우의 수 라고 하고요, cnt[a-1][...][...]에서 적절히 cnt[a][...][...] 를 구하는 식으로 해서 마지막에 cnt[단어사이즈-1][b][c] 를 모두 더한 수가 답이 됩니다.
한 가지 문제는, cnt[a][b][c]를 구할 때, cnt[a-1][...][...]들을 더해야 하는데, 유니콘이 한 스텝에 움직일 수 있는 (2+, 3+), (3+, 2+)의 좌표들을 모두 고려하면, 판의 대부분의 칸들에 대해서 저 값을 더해야 한다는 것입니다. 그림을 그려보면, 다음 위치에서만 유니콘이 올 수가 없습니다 - x 좌표 차이가 1 이하이거나, y 좌표 차이가 1 이하이거나, x 좌표 차이와 y 좌표 차이가 모두 2인 경우.
즉 (모든 위치에 대해서 합을 더한 값) - (x좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) - (y좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) + (x좌표 차이가 -1~1이고 y좌표 차이가 -1~1인 위치에 대해서 합을 더한 값) - (x좌표 차이가 2이고 y좌표 차이가 2인 위치에 대해서 합을 더한 값) 이 cnt[a][b][c] 가 됩니다. 여기서 '모든 위치에 대해서 합을 더한 값', 'x좌표가 i인 모든 위치에 대해서 합을 더한 값', 'y좌표가 j인 모든 위치에 대해서 합을 더한 값' 을 각 a에 대해서 한번만 계산하면, 이후의 계산을 O(1)로 할 수 있음을 알 수 있습니다.
실제 코드 구현도 이렇게 되어 있으니 보시면 쉽게 이해가 되실 것이라 생각합니다.
15년 전