드디어 에디토리얼을 쓰는 그 날이 왔습니다! 그러나 너무 옛날이라 가물가물하다능? 하악하악...
밀린 에디토리얼이 몇개인지는 모르겠지만 쓰면서 세어보죠.
Easy(250pt, CollectingRiders)
구현 위주의 문제입니다. 문제에서 요구하는 조건대로, 각 자리마다 판 위의 모든 나이트를 그 자리로 모으는 데 필요한 횟수를 계산해서 그 횟수의 최소치를 구하면 되겠지요. (a,b)->(c,d)까지 나이트가 움직이는 데 필요한 최소 횟수를 구하는 방법은 여러 가지가 있겠지만, 판이 작으므로 간단하게 플루이드로 처리했습니다.
[spoiler="코드 보기!"]~~~ cpp
#include
#include
#include
#include
#include
#include
using namespace std;
int y[8] = {1, 1, 2, 2, -1, -1, -2, -2};
int x[8] = {2, -2, 1, -1, 2, -2, 1, -1};
class CollectingRiders
{
public:
int minimalMoves(vector board)
{
int n = board.size();
int m = board[0].size();
int distance[100][100] = {0};
for (int i=0; i
for (int j=0; j
for (int k=0; k
for (int l=0; l
distance[i*m+j][k*m+l] = 999999;
for (int i=0; i
for (int j=0; j
distance[i*m+j][i*m+j] = 0;
for (int i=0; i
for (int j=0; j
for (int k=0; k<8; k++)
{
int ny = i+y[k];
int nx = j+x[k];
if (ny>=0 && nx>=0 && ny
distance[i*m+j][ny*m+nx] = 1;
}
for (int k=0; k
for (int i=0; i
for (int j=0; j
if (distance[i][k]+distance[k][j]
distance[i][j] = distance[i][k]+distance[k][j];
int mmin = 9999999;
for (int i=0; i
{
int now = 0;
for (int j=0; j
for (int k=0; k
if (board[j][k]!='.')
{
int rider = board[j][k]-'0';
int diff = distance[i][j*m+k];
if (diff>900000) now = 9999999;
now += (diff+rider-1)/rider;
}
printf("%d\n", now);
if (now
}
if (mmin >= 1000000) return -1;
return mmin;
};
};
# 지정된 언어 [/spoiler]를 찾을 수 없습니다. Medium(500pt, PointsOnACircle)
원 위에 주어진 점들을 빨간색 또는 파란색으로 칠하는데 빨간색 점들은 일정 각도로 회전하면 파란색 점과 겹쳐야 한다. 칠할 수 있는 점의 최대 갯수는?
이 문제도 역시 구현 위주의 문제입니다. 대략 4중 for로 처리를 했는데...
1. 회전해야 하는 각도를 정한다. (angle=1~180도, 181도 이상은 색깔을 바꿔주면 커버된다)
2. 어느 점에서 체크를 시작할지 정한다. (starter=0~angle-1도, 그러나 예를 들어 angle이 135도라면 0->135->270->45->180->325->90->225->0 이렇게 되므로 0도에서 시작하나 45도에서 시작하나 똑같다. 일반적으로는 0~gcd(angle, 360)-1도까지만 돌리면 된다는 것을 알 수 있다.)
3. 점이 359, 0, 1, 2도에 있다고 하자. 0도에서 1도단위로 체크하면 0도, 1도 점을 선택한 뒤에 2도와 359도 점은 남는다. 하지만 359도에서 시작하면 모든 점을 선택할 수 있다. 이런 경우를 처리하기 위해서, 0도에서 시작하는 경우와 1도에서 시작하는 경우의 두 가지 경우를 시도해본다. (다른 경우는 시도할 필요가 없다)
4. x, x+angle도의 점을 두개씩 선택해보면서, 이 두 점이 존재하면 선택해준다.
이렇게 했는데 좀 더 간단하게 짤 수도 있는 모양입니다.
[spoiler="코드 보기!"]~~~ cpp
#include <math.h>
#include <string.h>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
class PointsOnACircle
{
public:
int gcd(int a, int b)
{
while (b>0)
{
int c = a%b;
a=b;
b=c;
}
return a;
};
int color(vector <string> points)
{
string pl;
for (int i=0; i<points.size(); i++) pl += points[i];
pl += ' ';
vector<int> pts;
int data[360] = {0};
int now = 0;
for (int i=0; i<pl.size(); i++)
{
if (pl[i] == ' ') { data[now] = 1; now = 0; }
else now = now * 10 + pl[i]-'0';
}
int mmax = 0;
for (int angle=1; angle<=180; angle++)
{
int angle_gcd = gcd(angle, 360);
int iteration = 360/angle_gcd;
int now_sum = 0;
for (int starter = 0; starter<angle_gcd; starter++)
{
int now_max = 0;
for (int ccase = 0; ccase<2; ccase++)
{
int now = 0;
for (int iter = 0; iter < iteration; iter++)
{
int angle1 = (starter+(iter+ccase)*angle)%360;
int angle2 = (starter+(iter+1+ccase)*angle)%360;
if (data[angle1]==1 && data[angle2]==1)
{
now += 2;
data[angle1] = data[angle2] = 2;
}
}
if (now>now_max) now_max = now;
for (int iter = 0; iter < iteration; iter++)
{
int angle1 = (starter+(iter+ccase)*angle)%360;
if (data[angle1]==2)
data[angle1] = 1;
}
// printf("%d ", now);
}
now_sum += now_max;
}
if (now_sum>mmax) mmax = now_sum;
// printf("%d %d %d\n", angle, angle_gcd, now_sum);
}
return mmax;
};
};
~~~[/spoiler]
Hard(1000pt, CharmingTickets)
0-9까지 수들 중에서 주어진 몇 개 수들로만 만들어진 2*K자리 티켓이 있는데 홀수자리 짝수자리 합이 같거나 앞 절반 뒤 절반 합이 같아야 한다.
쉽지 않게 보이지만 사실은 중학교 수학으로 해결할 수 있습니다.
1) 홀수자리 짝수자리 합이 같은 경우의 수 = 앞 절반 뒤 절반의 합이 같은 경우의 수 = 임의의 K자리 수의 합이 다른 임의의 K자리 수의 합과 같은 경우의 수
K자리 수의 합 = K자리 수의 합 이 되는 경우의 수를 Count2(K, good)이라고 정의합시다. 여기서 good은 티켓을 구성하라고 주어진 수들입니다.
2) 홀수자리 짝수자리 합이 같고 앞 절반 뒤 절반의 합이 같은 경우의 수
(앞 절반에서 홀수자리 = 뒤 절반에서 짝수자리) AND (앞 절반에서 짝수자리 = 뒤 절반에서 홀수자리) 가 되어야 합니다.
이 때 K가 짝수인 경우와 홀수인 경우가 다릅니다.
K가 짝수: 경우의 수는 Count2(K/2, good) * Count2(K/2, good)
K가 홀수: 경우의 수는 Count2(K/2+1, good) * Count2(K/2, good)
3) 결과는 1) + 1) - 2)가 됩니다.
이제 Count2(K, good)을 구해야 합니다. 저는 DP로 해결했는데, diff[i][j] = (첫번째 i자리 수)-(두번째 i자리 수)가 j인 경우라고 놓으면 diff[i+1][j]는 diff[i+1][j-9]~diff[i+1][j+9]를 이용해서 구할 수 있습니다.
이 때 j가 0 미만이 될 수 있으므로 첨자에 적당한 수를 더해서 계산하면 됩니다. 또한 modular 999983을 계산할 때마다 적용해야 합니다.
[spoiler="코드 보기!"]~~~ cpp
#include <math.h>
#include <string.h>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
int modular = 999983;
class CharmingTickets
{
public:
int count2(int K, string good)
{
int charming[10] = {0};
for (int i=0; i<good.size(); i++) charming[good[i]-'0'] = 1;
int diff_case[19] = {0};
for (int i=0; i<10; i++)
for (int j=0; j<10; j++)
if (charming[i] && charming[j])
diff_case[i-j+9] ++;
int diff1[19999] = {0};
int diff2[19999] = {0};
diff1[0] = 1;
for (int i=0; i<K; i++)
{
for (int j=(i+1)*18; j>=0; j--)
{
diff2[j] = 0;
for (int k=0; k<19 && k<=j; k++)
diff2[j] += diff1[j-k]*diff_case[k];
}
for (int j=0; j<19999; j++)
diff1[j] = diff2[j]%modular;
}
return diff1[9*K];
}
int count(int K, string good)
{
int t1 = count2(K, good);
int t2 = 0;
if (K%2==0)
{
// even
long long p1 = count2(K/2, good);
t2 = (p1*p1)%modular;
}
else
{
// odd
long long p1 = count2(K/2, good);
long long p2 = count2(K/2+1, good);
t2 = (p1*p2)%modular;
}
return (t1+t1-t2+modular)%modular;
};
};
~~~[/spoiler]
<div>[이 글은 과거 홈페이지에서 이전된 글입니다. <a href="http://algospot.andromeda-express.com/zbxe/editorial/45293">원문보기</a>]</div>
16년 전
0개의 댓글이 있습니다.
정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면
온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야
합니다. 현재 문제를 푸셨습니다.
일루
드디어 에디토리얼을 쓰는 그 날이 왔습니다! 그러나 너무 옛날이라 가물가물하다능? 하악하악...
밀린 에디토리얼이 몇개인지는 모르겠지만 쓰면서 세어보죠.
Easy(250pt, CollectingRiders)
구현 위주의 문제입니다. 문제에서 요구하는 조건대로, 각 자리마다 판 위의 모든 나이트를 그 자리로 모으는 데 필요한 횟수를 계산해서 그 횟수의 최소치를 구하면 되겠지요. (a,b)->(c,d)까지 나이트가 움직이는 데 필요한 최소 횟수를 구하는 방법은 여러 가지가 있겠지만, 판이 작으므로 간단하게 플루이드로 처리했습니다.
[spoiler="코드 보기!"]~~~ cpp
#include board)
for (int j=0; j
for (int k=0; k
for (int l=0; l
distance[i*m+j][k*m+l] = 999999;
for (int j=0; j
distance[i*m+j][i*m+j] = 0;
for (int j=0; j
for (int k=0; k<8; k++)
distance[i*m+j][ny*m+nx] = 1;
for (int i=0; i
for (int j=0; j
if (distance[i][k]+distance[k][j]
distance[i][j] = distance[i][k]+distance[k][j];
{
for (int k=0; k
if (board[j][k]!='.')
}
#include
#include
#include
#include
#include
using namespace std;
int y[8] = {1, 1, 2, 2, -1, -1, -2, -2};
int x[8] = {2, -2, 1, -1, 2, -2, 1, -1};
class CollectingRiders
{
public:
int minimalMoves(vector
{
int n = board.size();
int m = board[0].size();
int distance[100][100] = {0};
for (int i=0; i
for (int i=0; i
for (int i=0; i
{
int ny = i+y[k];
int nx = j+x[k];
if (ny>=0 && nx>=0 && ny
}
for (int k=0; k
int mmin = 9999999;
for (int i=0; i
int now = 0;
for (int j=0; j
{
int rider = board[j][k]-'0';
int diff = distance[i][j*m+k];
if (diff>900000) now = 9999999;
now += (diff+rider-1)/rider;
}
printf("%d\n", now);
if (now
if (mmin >= 1000000) return -1;
return mmin;
};
};
16년 전