[2020년 1월 9일]는 NOIP 시뮬레이션 레이스 (DAY1)의 설정을 개선
시험 결과는 할 수없는 시간이 지나면 두 가지 질문, 제목 부족의 속도로 수행, 첫 번째 두 가지 질문에 만족하지 않습니다.
source : 100 + 20 + 0 + 0 = 120 rank7
매우 비우호적.
글쎄, 그건 입력
\ (T1 \)
포털 : [USACO17JAN] 암소 소 댄스 댄스 쇼
분석
신선한 물 문제, 그것은 절반의 답을 생각하기 쉽고, 모노톤을 증명하기 쉽습니다.
그런 다음 허용을 고려 \ (\ 확인)
때 첫 번째 스택 유지되는 시간에 따라, 작은 힙 루트를 분석.
그런 다음 - 잘라
약간의 코드를
\ (T2 \)
포털 : [USACO17JAN]가 발굽 ,, 종이, 가위 발굽 가위 ...
현재가 더 어려울 수 없어야 합니다 (DP \) \ 있지만에 직접적인 타격을 전송하는 누설 검사 감소 방법을 고려 \ (20 \) 분.
문제의 의미에 따라 쉬운 상태 설정 생각 \ (F_는 {난, J, K가} \) 제 나타낸다 \ (I \) 의 변화가, 라운드 \ (j \) , 배 기회와 현재이다 \ (K \) ( H / S / P가 설정된다 \ (1/2/3 \) )
이체 :
설정 \ (P \) \ (Q는 \) 와 달리 나타낸다 (\ K \) 다른 두 개의 제스처, \ (승리 [I]가 [j]가 \)은 제스처 나타내는 \ (I \) 승 제스처 \ (J를 \) \ (a는 [I]는 \) 현재 나타냄 ) \ (\ FJ 가 제스처 :
\ [F [I] [J]를 [K]는 최대 = (F [I-1] [J-1] [P], F [I-1] [J-1] [Q], F [I-1] [J] [케이 ]) + 승 [K] 이 [I] \]
코드
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 1e5;
int n , k , a[N + 5] , f[N + 5][25][4] , ans = 0 , p , q;
char ch;
int data[4][4];
int main()
{
// freopen("hps.in" , "r" , stdin);
// freopen("hps.out" , "w" , stdout);
scanf("%d%d" , &n , &k);
for(register int i = 1; i <= n; i++)
{
ch = getchar();
while (ch != 'H' && ch != 'P' && ch != 'S') ch = getchar();
if (ch == 'H') a[i] = 1;
else if (ch == 'P') a[i] = 2;
else if (ch == 'S') a[i] = 3;
}
data[1][3] = data[2][1] = data[3][2] = 1;
for(register int i = 1; i <= n; i++)
for(register int j = 1; j <= 3; j++)
f[i][0][j] = f[i - 1][0][j] + data[j][a[i]];
for(register int i = 1; i <= n; i++)
for(register int j = 1; j <= k; j++)
for(register int l = 1; l <= 3; l++)
{
if (l == 1) p = 2 , q = 3;
else if (l == 2) p = 1 , q = 3;
else if (l == 3) p = 1 , q = 2;
f[i][j][l] = max(f[i - 1][j][l] + data[l][a[i]], max(f[i - 1][j - 1][p] + data[l][a[i]] , f[i - 1][j - 1][q] + data[l][a[i]]));
}
for(register int i = 0; i <= k; i++)
for(register int j = 1; j <= 3; j++)
ans = max(f[n][i][j] , ans);
printf("%d" , ans);
}
사라 ??????
\ (T3 \)
포털 : [USACO17JAN] 암소 탐색 소 탐색
코드입니다 어렵지만 내용과 더 많은 질문 많은 양의하지
(태그 \) \ :와 \ (BFS \) 시뮬레이션 할 \ (DP \)
는 다음과 같이 구체적으로 분석을 :
첫 번째 변환 : 때문에 우리가 시작점으로 설정하므로,지도 이유 판독 \ ((N, 1) \ ) , 엔드 포인트 (\ (1, N) \
) 은 각각 두 개의 소가 \ ((N, 1) \ ) 2 개 종 방향 대향를
그리고 참고 : 상관없이 다른 가축, 그는 움직이지 않는 것, 새로운 명령을 무시하지 않는 소를 종료합니다, 현재 명령이 소가 선이 움직이지 않은 교차했을 경우. (피사체에 더 심각한 얼굴 용)
집합 \ (F_는 {X1은, Y1, D1, X2, Y2, D2는} \) 소 도착 나타내는 \ ((X1, Y1) \ ) 대향 \ (D1 \) , 소 두 도착 \ ((X2, Y2)를 \ ) 에 대한 \ (D2 \) 명령어 최소 길이
의한 각각의 명령의 기여도에 대답 \ (1 \) , 그것을 사용하는 것이 가능하다 ) \ \합니다 (BFS 가장 짧은 측부 연장 업데이트 할 ) \ (\ DIS
하지만 실제로 기절 공간을 최적화 할 수 있습니다 \ (D2 \) 그 차원
이 개 소는 동일한 명령을 수신하기 때문에, 자신의 방향에 따라 다른 측면을 알 수있을 것입니다 어느 알고, 상대적으로 좋은의 생각을 으로 시작
코드
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 20;
int n , map[N + 5][N + 5] , head , tail , ans = 1e5;
int f[N + 5][N + 5][4][N + 5][N + 5][4] , vis[N + 5][N + 5][4][N + 5][N + 5][4];
int fx[4][2] = { -1 , 0 , 0 , 1 , 1 , 0 , 0 , -1 };
char ch;
struct node{
int x1 , y1 , d1 , x2 , y2 , d2;
}q[N * N * N * N * 16 + 10];
inline bool check(int x , int y , int xx , int yy)
{
return (x <= 0 || y <= 0 || x > n || y > n || map[x][y] == 1 || (xx == 1 && yy == n));
}
int main()
{
// freopen("cow.in" , "r" , stdin);
// freopen("cow.out" , "w" , stdout);
scanf("%d" , &n);
for(register int i = 1; i <= n; i++)
for(register int j = 1; j <= n; j++)
{
while (ch != 'E' && ch != 'H') ch = getchar();
if (ch == 'H') map[i][j] = 1;
ch = getchar();
}
q[++tail] = (node){n , 1 , 0 , n , 1 , 1};
memset(f , 0x3f , sizeof(f));
f[n][1][0][n][1][1] = 0;
vis[n][1][0][n][1][1] = 1;
while (head < tail)
{
struct node now = q[++head];
int x1 , y1 , d1 , x2 , y2 , d2;
d1 = now.d1 , d2 = now.d2;
x1 = now.x1 + fx[d1][0] , y1 = now.y1 + fx[d1][1];
if (check(x1 , y1 , now.x1 , now.y1)) x1 = now.x1 , y1 = now.y1;
x2 = now.x2 + fx[d2][0] , y2 = now.y2 + fx[d2][1];
if (check(x2 , y2 , now.x2 , now.y2)) x2 = now.x2 , y2 = now.y2;
if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0)
{
q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2};
f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1;
vis[x1][y1][d1][x2][y2][d2] = 1;
}
d1 = (now.d1 + 1) % 4 , d2 = (now.d2 + 1) % 4;
x1 = now.x1 , y1 = now.y1 , x2 = now.x2 , y2 = now.y2;
if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0)
{
q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2};
f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1;
vis[x1][y1][d1][x2][y2][d2] = 1;
}
d1 = (now.d1 + 3) % 4 , d2 = (now.d2 + 3) % 4;
x1 = now.x1 , y1 = now.y1 , x2 = now.x2 , y2 = now.y2;
if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0)
{
q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2};
f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1;
vis[x1][y1][d1][x2][y2][d2] = 1;
}
}
for(register int i = 0; i < 4; i++)
for(register int j = 0; j < 4; j++)
ans = min(ans , f[1][n][i][1][n][j]);
printf("%d" , ans);
}
\ (T4 \)
포털 : 서브 시퀀스 반전 역순는 [USACO17JAN]
해석이 아니라 다음 :
이 제목을 시작하는 것은 불가능 것입니다 실제로는 매우 일상적인 간격 \ (민주당이 \)
만을 값에 따라 (1 ~ 50 \) \ 특성, 우리는 마법의 작업을 사용할 수 있습니다 노크 소위 플립
ADO, 룩
세트 \ (F_을 {I, J, 상하} \) 의 간격을 나타내는 \ ([I, J] \) 의 수치 범위 (\ [DOWN, UP] \) 긴 시퀀스의 길이는
다음 간격 합니다 (DP \) \ 루틴 전송하지만, 두 부분이 서로 중첩되어 전이
코드
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 50;
int n , f[N + 5][N + 5][N + 5][N + 5] , a[N + 5] , Mx;
int main()
{
// freopen("reversal.in" , "r" , stdin);
// freopen("reversal.out" , "w" , stdout);
scanf("%d" , &n);
for(register int i = 1; i <= n; i++)
{
scanf("%d" , &a[i]);
for(register int down = 1; down <= a[i]; down++)
for(register int up = a[i]; up <= 50; up++)
f[i][i][down][up] = 1;
}
for(register int len1 = 2; len1 <= n; len1++)
for(register int i = 1; i <= n - len1 + 1; i++)
{
register int j = i + len1 - 1;
for(register int len2 = 2; len2 <= 50; len2++)
for(register int down = 1; down <= 51 - len2; down++)
{
register int up = down + len2 - 1 , Mx;
Mx = max(f[i][j][down + 1][up] , f[i][j][down][up - 1]);
Mx = max(f[i + 1][j][down][up] + (a[i] == down) , Mx);
Mx = max(f[i][j - 1][down][up] + (a[j] == up) , Mx);
Mx = max(f[i + 1][j - 1][down][up] + (a[j] == down) + (a[i] == up) , Mx);
f[i][j][down][up] = Mx;
}
}
printf("%d" , f[1][n][1][50]);
}