传送门:【codeforces】Codeforces Round #279 (Div. 2)
数量就是1,2,3中最小的那个。模拟即可,用vector超级方便,不过我还是用了邻接表。。(我有特殊的作死技巧)
#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\n" , 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\n" , a[i] , b[i] , c[i] ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
对每对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 ? ' ' : '\n' ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
将字符串拆成两份,假设我们从位置i断开得到两个数x,y,那么我们可以O(1)递推得到i+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\n" ) ; For ( j , 0 , i ) printf ( "%c" , s[j] ) ; printf ( "\n" ) ; rep ( j , i + 1 , n ) printf ( "%c" , s[j] ) ; printf ( "\n" ) ; return ; } } printf ( "NO\n" ) ; } int main () { while ( ~scanf ( "%s%d%d" , s , &a , &b ) ) solve () ; return 0 ; }
首先得到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较多的那个面积的三转化成2,易知这个是一定要进行的。然后再将2较多的面积中把多余的2去掉,如果这样处理以后两个矩形的最终面积相同则有解,否则无解。
PS:我觉得暴力会好写很多,对矩形1处理得到所有面积排个序,同时记录最后a1,b1变成的值和所用的最小步数,然后同样对矩形2处理,对得到的面积在矩形1中二分看是否能找到,能的话就更新解。然后就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\n" , cnt ) ; } void solve () { int cnt = 0 ; LL x1 = ( LL ) a1 * b1 ; LL x2 = ( LL ) a2 * b2 ; LL x = gcd ( x1 , x2 ) ; //printf ( "%d\n" , 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\n" ) ; 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\n" ) ; 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\n" ) ; 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\n" ) ; return ; } } if ( x1 != x2 ) { printf ( "-1\n" ) ; return ; } printf ( "%d\n" , cnt ) ; printf ( "%d %d\n" , a1 , b1 ) ; printf ( "%d %d\n" , a2 , b2 ) ; } int main () { while ( ~scanf ( "%d%d%d%d" , &a1 , &b1 , &a2 , &b2 ) ) solve () ; return 0 ; }
490E. 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\n" ) ; 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\n" ) ; return ; } a[i].num = now ; pre = now ; } printf ( "YES\n" ) ; For ( i , 1 , n ) printf ( "%d\n" , 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 ; }
不会正解,但是稍微计算了一下复杂度,常数小的O(N^2logN)可以卡过。
方法是枚举根,然后dfs,进入这个点的时候将这个点按照二分求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\n" , ans ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }