[codeforces] Codeforces Round #279(Div.2) 문제 해결
12670 단어 codeforces
490A. Team Olympiad
수량이 1, 2, 3 중에 제일 작은 거요.시뮬레이션을 하면 돼요. 벡터를 사용하면 아주 편리해요. 하지만 저는 인접표를 썼어요.(나는 특별한 죽음의 기교가 있다)
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , Graph.bcc_cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
const int MAXE = 100005 ;
struct Edge {
int v , n ;
Edge () {}
Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;
Edge E[MAXE] ;
int H[4] , cntE ;
int a[MAXN] , b[MAXN] , c[MAXN] ;
int all[4] ;
int n ;
void clear () {
cntE = 0 ;
clr ( H , -1 ) ;
clr ( all , 0 ) ;
}
void addedge ( int u , int v ) {
E[cntE] = Edge ( v , H[u] ) ;
H[u] = cntE ++ ;
}
void solve () {
int x ;
clear () ;
For ( i , 1 , n ) {
scanf ( "%d" , &x ) ;
addedge ( x , i ) ;
all[x] ++ ;
}
int m = min ( min ( all[1] , all[2] ) , all[3] ) ;
printf ( "%d
" , m ) ;
int cnt ;
cnt = 0 ;
for ( int i = H[1] ; ~i ; i = E[i].n ) {
a[cnt ++] = E[i].v ;
if ( cnt == m ) break ;
}
cnt = 0 ;
for ( int i = H[2] ; ~i ; i = E[i].n ) {
b[cnt ++] = E[i].v ;
if ( cnt == m ) break ;
}
cnt = 0 ;
for ( int i = H[3] ; ~i ; i = E[i].n ) {
c[cnt ++] = E[i].v ;
if ( cnt == m ) break ;
}
rep ( i , 0 , m ) printf ( "%d %d %d
" , a[i] , b[i] , c[i] ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}
490B. Queue
매 쌍의ai,bi에 대해next[ai]=bi를 설정하면 0부터next를 따라 가면 짝수인 사람의 번호를 쉽게 알 수 있다.
그리고 우리는 모든 사람에게 선구자pre[bi]=ai를 기록한다. 위치가 1인 사람은 선구가 없기 때문에 이 사람을 다시 찾는다. 이 사람부터next를 따라 가면 위치가 홀수인 사람의 번호를 벗어날 수 있다.
이 문제에 이르러 해결하다.
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , Graph.bcc_cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 1000005 ;
const int MAXE = 100005 ;
int next[MAXN] ;
int pos[MAXN] ;
int use[MAXN] ;
int p[MAXN] ;
int n ;
void solve () {
int x , y ;
clr ( next , 0 ) ;
clr ( use , 0 ) ;
rep ( i , 0 , MAXN ) p[i] = i ;
For ( i , 1 , n ) {
scanf ( "%d%d" , &x , &y ) ;
next[x] = y ;
use[x] = use[y] = 1 ;
p[y] = x ;
}
x = 0 , y = 2 ;
while ( next[x] ) {
pos[y] = next[x] ;
y += 2 ;
x = next[x] ;
}
For ( i , 1 , 1000000 ) {
if ( !use[i] ) continue ;
if ( p[i] == i ) {
x = i ;
break ;
}
}
y = 1 ;
while ( x ) {
pos[y] = x ;
y += 2 ;
x = next[x] ;
}
For ( i , 1 , n ) printf ( "%d%c" , pos[i] , i < n ? ' ' : '
' ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}
490 C. Hacking Cypher 문자열을 두 부로 나누어 위치 i에서 두 개의 수 x, y를 끊었다고 가정하면, i+1에서 두 개의 수를 O(1)로 추정할 수 있습니다.
x1 = (x* 10 + s[i + 1])% a, y1 = (y* 10 - s[i + 1]* pow[n - i - 2])% b, 그중 pow[i]=10 ^i, pow[i]=pow[i - 1]%b.
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , Graph.bcc_cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 1000005 ;
const int MAXE = 100005 ;
char s[MAXN] ;
LL pow[MAXN] ;
int a , b ;
void solve () {
int L = 0 , R = 0 ;
int n = strlen ( s ) ;
pow[0] = 1 ;
rep ( i , 1 , MAXN ) pow[i] = pow[i - 1] * 10 % b ;
rep ( i , 0 , n ) R = ( R * 10 + s[i] - '0' ) % b ;
rep ( i , 0 , n - 1 ) {
L = ( L * 10 + s[i] - '0' ) % a ;
R = ( R - ( s[i] - '0' ) * pow[n - i - 1] % b + b ) % b ;
if ( L == 0 && R == 0 && s[i + 1] != '0' ) {
printf ( "YES
" ) ;
For ( j , 0 , i ) printf ( "%c" , s[j] ) ;
printf ( "
" ) ;
rep ( j , i + 1 , n ) printf ( "%c" , s[j] ) ;
printf ( "
" ) ;
return ;
}
}
printf ( "NO
" ) ;
}
int main () {
while ( ~scanf ( "%s%d%d" , s , &a , &b ) ) solve () ;
return 0 ;
}
490D. Chocolate
먼저 a1*b1, a2*b2를 얻어 그들의 gcd(a1*b1, a2*b2)=x를 얻어 답을 쉽게 알 수 있다. 만약에 존재한다면 면적은 반드시 그들의 gcd의 배수이다. 그리고 a1*b1/x중 2의 개수, a2*b2/x중 2의 개수, a1*b1/x중 3의 개수, a2*b2/x중 3의 개수를 얻는다.그리고 우리는 3이 많은 그 면적의 3을 2로 바꾸는데 이것은 반드시 진행해야 한다는 것을 알기 쉽다.그리고 2가 비교적 많은 면적에서 나머지 2를 제거하고 이렇게 처리한 후에 두 직사각형의 최종 면적이 같으면 해가 있고 그렇지 않으면 해가 없다.
PS: 폭력은 많이 쓸 수 있다고 생각합니다. 직사각형 1을 처리하면 모든 면적을 순서대로 배열하고 마지막 a1, b1이 변하는 값과 사용하는 최소 걸음수를 기록합니다. 그리고 직사각형 2를 똑같이 처리하고 얻은 면적을 직사각형 1에서 2분으로 나누어 찾을 수 있는지 확인하고 가능하면 업데이트를 합니다.그리고 OK.
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
const int MAXE = 200005 ;
int a[2] , b[2] ;
int a1 , b1 , a2 , b2 ;
inline LL gcd ( LL a , LL b ) {
return b ? gcd ( b , a % b ) : a ;
}
inline void divide ( LL a , int b , int &cnt ) {
for ( cnt = 0 ; a % b == 0 ; a /= b ) ++ cnt ;
//printf ( "%d
" , cnt ) ;
}
void solve () {
int cnt = 0 ;
LL x1 = ( LL ) a1 * b1 ;
LL x2 = ( LL ) a2 * b2 ;
LL x = gcd ( x1 , x2 ) ;
//printf ( "%d
" , x ) ;
divide ( x1 / x , 2 , a[0] ) ;
divide ( x2 / x , 2 , a[1] ) ;
divide ( x1 / x , 3 , b[0] ) ;
divide ( x2 / x , 3 , b[1] ) ;
while ( b[0] > b[1] ) {
-- b[0] ;
++ a[0] ;
x1 = x1 / 3 * 2 ;
++ cnt ;
if ( a1 % 3 == 0 ) a1 = a1 / 3 * 2 ;
else if ( b1 % 3 == 0 ) b1 = b1 / 3 * 2 ;
else {
printf ( "-1
" ) ;
return ;
}
}
while ( b[1] > b[0] ) {
-- b[1] ;
++ a[1] ;
x2 = x2 / 3 * 2 ;
++ cnt ;
if ( a2 % 3 == 0 ) a2 = a2 / 3 * 2 ;
else if ( b2 % 3 == 0 ) b2 = b2 / 3 * 2 ;
else {
printf ( "-1
" ) ;
return ;
}
}
while ( a[0] > a[1] ) {
-- a[0] ;
++ cnt ;
x1 /= 2 ;
if ( a1 % 2 == 0 ) a1 /= 2 ;
else if ( b1 % 2 == 0 ) b1 /= 2 ;
else {
printf ( "-1
" ) ;
return ;
}
}
while ( a[1] > a[0] ) {
-- a[1] ;
++ cnt ;
x2 /= 2 ;
if ( a2 % 2 == 0 ) a2 /= 2 ;
else if ( b2 % 2 == 0 ) b2/= 2 ;
else {
printf ( "-1
" ) ;
return ;
}
}
if ( x1 != x2 ) {
printf ( "-1
" ) ;
return ;
}
printf ( "%d
" , cnt ) ;
printf ( "%d %d
" , a1 , b1 ) ;
printf ( "%d %d
" , a2 , b2 ) ;
}
int main () {
while ( ~scanf ( "%d%d%d%d" , &a1 , &b1 , &a2 , &b2 ) ) solve () ;
return 0 ;
}
490 E. Restoring Increasing Sequence 나는 이 문제가 훨씬 간단하다고 생각한다.
모든 수를 최대로 바꿀 수 있는 수(?를 9로 바꿀 수 있는 수)로 바꾸고 그 다음에 높은 자리에서 하나하나 줄여서 이 방법으로 이전보다 큰 가장 작은 수를 찾아라.찾지 못하면 해가 없다.나는 이 문제가 짜증나는 것이 바로 시뮬레이션이라고 생각한다. AC가 한 번 더 괜찮다. 그렇지 않으면 음이 모두 아프다.
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , Graph.bcc_cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
const int MAXE = 100005 ;
const int L = 9 ;
struct Node {
int num , n ;
int digit[L] ;
int unknow[L] ;
} ;
Node a[MAXN] ;
int pow[L] ;
char s[L] ;
int n ;
void solve () {
clr ( a , 0 ) ;
int flag = 0 ;
For ( i , 1 , n ) {
scanf ( "%s" , s ) ;
a[i].n = strlen ( s ) ;
if ( s[0] == '0' ) flag = 1 ;
rep ( j , 0 , a[i].n ) {
if ( s[j] == '?' ) {
a[i].num = a[i].num * 10 + 9 ;
a[i].digit[a[i].n - j - 1] = 9 ;
a[i].unknow[a[i].n - j - 1] = 1 ;
} else {
a[i].num = a[i].num * 10 + s[j] - '0' ;
a[i].digit[a[i].n - j - 1] = s[j] - '0' ;
}
}
}
if ( flag ) {
printf ( "NO
" ) ;
return ;
}
int pre = 0 ;
For ( i , 1 , n ) {
int first = 1 , now = a[i].num ;
rev ( j , a[i].n - 1 , 0 ) {
if ( a[i].unknow[j] == 0 ) {
first = 0 ;
continue ;
}
int up = first ? 8 : 9 ;
rep ( k , 0 , up ) {
if ( now - pow[j] <= pre ) break ;
now -= pow[j] ;
}
first = 0 ;
}
if ( now <= pre ) {
printf ( "NO
" ) ;
return ;
}
a[i].num = now ;
pre = now ;
}
printf ( "YES
" ) ;
For ( i , 1 , n ) printf ( "%d
" , a[i].num ) ;
}
int main () {
pow[0] = 1 ;
rep ( i , 1 , 10 ) pow[i] = pow[i - 1] * 10 ;
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}
490F. Treeland Tour
정해는 아니지만 복잡도를 조금 계산해 보니 상수가 작은 O(N^2logN)는 끊길 수 있다.
방법은 매거근을 열거한 다음에 dfs입니다. 이 점에 들어갈 때 이 점을 2분구LIS의 방법에 따라 창고에 추가하고 최우수치를 업데이트합니다. 이 점을 떠날 때 창고의 요소를 바꾸면 됩니다.이 방법의 상수는 아직 매우 작다. 처음에 나는 라인 트리로 이 절차를 완성했다.TLE가...역시 너무 어려...
폭력적이지 않은 걸 어떻게 해야 할지 생각이 안 났어요. -
#include <set>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , cnt
#define mid ( ( l + r ) >> 1 )
const int MAXN = 100005 ;
const int MAXE = 200005 ;
struct Edge {
int v , n ;
Edge () {}
Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;
Edge E[MAXE] ;
int H[MAXN] , cntE ;
int val[MAXN] ;
int n ;
int S[MAXN] ;
int ans ;
void clear () {
cntE = 0 ;
clr ( H , -1 ) ;
}
void addedge ( int u , int v ) {
E[cntE] = Edge ( v , H[u] ) ;
H[u] = cntE ++ ;
}
int search ( int x , int l , int r ) {
while ( l < r ) {
int m = mid ;
if ( val[S[m]] >= x ) r = m ;
else l = m + 1 ;
}
return l ;
}
void dfs ( int u , int top = 0 , int fa = 0 ) {
int pos , tmp ;
if ( !top || val[S[top - 1]] < val[u] ) {
S[top ++] = u ;
ans = max ( ans , top ) ;
pos = top - 1 ;
} else {
pos = search ( val[u] , 0 , top - 1 ) ;
tmp = S[pos] ;
S[pos] = u ;
}
for ( int i = H[u] ; ~i ; i = E[i].n ) if ( E[i].v != fa ) dfs ( E[i].v , top , u ) ;
S[pos] = tmp ;
}
void solve () {
ans = 0 ;
int u , v ;
clear () ;
For ( i , 1 , n ) scanf ( "%d" , &val[i] ) ;
rep ( i , 1 , n ) {
scanf ( "%d%d" , &u , &v ) ;
addedge ( u , v ) ;
addedge ( v , u ) ;
}
For ( i , 1 , n ) dfs ( i ) ;
printf ( "%d
" , ans ) ;
}
int main () {
while ( ~scanf ( "%d" , &n ) ) solve () ;
return 0 ;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Codeforces Round #715 Div. 2C The Sports Festival: 구간 DP전형구간 DP의 초전형. 이하, 0-indexed. 입력을 정렬하여 어디서나 시작하고 최적으로 좌우로 계속 유지하면 좋다는 것을 알 수 있습니다. {2000})$의 주문이 된다. 우선, 입력을 소트하여 n개의 요소를 $...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.