2013 Aizu Regional Contest(UValive 6661,6662,6663,6664,6665,6669)

A - Equal Sum Sets

題意:

輸入三個數 n, k, s .
求有多少種集合元素個數爲k,元素最大值爲n,元素之和爲s,集合中元素均不相同.

思路:

  1. 暴力
    由於 n20 ,那麼只有 220=106 種集合,那麼枚舉集合判斷是否符合條件即可,複雜度爲 O(2nk) ,但由於有100組樣例。。所以只能很勉強地過,n 再大一點就得跪。
    並不推薦這種做法。。
  2. DP
    dp[i][j][k]表示 n = i , k = j , s = k 的集合數,dp[i][j][k]可以由兩種狀態轉移得到,一種是集合中有元素 i 的,一種是沒有的。
    dp[i][j][k]=dp[i1][j][k]+dp[i1][j1][ki]

代碼1(暴力):

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n , k , s ;
    while ( cin >> n >> k >> s ) {
        if ( !n && !k && !s ) break ;
        int total = ( 1 << n ) ;
        int ans = 0 ;
        for ( int i = 0 ; i < total ; i++ ) {
            int tmp = i , sum = 0 ;
            int a = 1 , cnt = 0 ;
            while ( tmp ) {
                if ( tmp & 1 ) {
                    sum += a ;
                    cnt++ ;
                    if ( sum > s || cnt > k ) break ;
                }
                a++ ; tmp >>= 1 ;
            }
            if ( sum == s && cnt == k ) ans ++ ;
        }
        cout << ans << endl ;
    }
    return 0;
}

代碼2(DP):

#include<bits/stdc++.h>
using namespace std;

int n , k , s ;
int dp[22][12][200] ;

void init()
{
    dp[0][0][0] = 1 ;
    for ( int i = 1 ; i <= 20 ; i++ ) 
        for ( int j = 0 ; j <= 10 ; j++ ) 
            for ( int k = 0 ; k <= 160 ; k++ ) 
            {
                dp[i][j][k] = dp[i-1][j][k] ;
                if ( j && k >= i )
                    dp[i][j][k] += dp[i-1][j-1][k-i] ;
            }
}
int main()
{
    init() ;
    while ( ~scanf( "%d%d%d" ,&n ,&k ,&s ) ) 
    {
        if ( !n && !k && !s ) break ;
        printf( "%d\n" , dp[n][k][s] ) ;
    }
    return 0;
}

B - The Last Ant

題意:

輸入兩個數 n , l .
n 代表螞蟻的數量,l 代表木板的長度,接下來輸入 n 只螞蟻所在的位置與行動的方向。
若兩隻螞蟻在相鄰的兩格之間相遇,則掉頭而行;若相遇位置在一格中心,則繼續沿原方向前進。
已知螞蟻速度爲 1 格/s,求所有螞蟻都掉下木板所需的時間,並求出最後一個離開木板的螞蟻編號。

思路:

模擬,模擬,模擬。。

代碼:

#include<bits/stdc++.h>
using namespace std;

struct Ant{
    int id, pos, leave;
    char dir[2] ;
    bool operator < ( const Ant &a )const {
        return pos < a.pos ;
    }
};
Ant a[25] ;
int n , l ;
void turn( int i , int j ) {
    if ( a[i].dir[0] == 'L' ) a[i].dir[0] = 'R' ;
    else a[i].dir[0] = 'L' ;
    if ( a[j].dir[0] == 'L' ) a[j].dir[0] = 'R' ;
    else a[j].dir[0] = 'L' ;
}
void work()
{
    int time = 0 ;
    int out = 0 ;
    Ant last[2] ;
    while ( 1 ) {
        time ++ ;
        for ( int i = 0 ; i < n ; i++ ) {
            if ( a[i].pos <= 0 || a[i].pos >= l ) continue ;
            if ( a[i].dir[0] == 'R' ) a[i].pos++ ;
            else a[i].pos-- ;
            if ( a[i].pos == 0 || a[i].pos == l ) {
                out++ ; a[i].leave = time ;
                last[out&1] = a[i] ;
            }
        }
        sort( a , a + n ) ;
        for ( int i = 0 ; i < n - 1 ; i++ ) {
            if ( a[i].pos == a[i+1].pos ) 
                turn( i , i+1 ) ;
        }
        if ( out >= n ) break ;
    }
    int ans = last[out&1].id;
    if ( last[1].leave == last[0].leave ) {
        if ( last[0].dir[0] == 'L' )
            ans = last[0].id ;
        else 
            ans = last[1].id ;
    } 
    cout << time << ' ' << ans << endl ;
}
int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);
    while ( scanf( "%d%d" ,&n ,&l ) , n || l ) {
        for ( int i = 0 ; i < n ; i++ ) {
            scanf( "%s%d" ,a[i].dir ,&a[i].pos ) ;
            a[i].id = i + 1 ;
        }
        sort( a , a + n ) ;
        work() ;
    }
    return 0;
}

C - Count the Regions

題意:

給 n 個矩形的座標,計算整個平面被矩形分成了幾個區域。

思路:

先離散化,然後把所有矩形邊標記爲1,然後枚舉每一個圖內的點,若標記爲0則dfs染色,遇到邊界停止,並且將答案+1.

代碼:

//2015/11/1 13:55:53
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<ctime>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl 
#define pri( x ) cout << #x << " = " << x << " " 
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case %d: " , kase++ )
#define sqr( x ) ( x * x )
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
typedef long long lint;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;

struct Rec{
    int l , r , t , b ;
    void input() {
        scanf( "%d%d%d%d" ,&l ,&t ,&r ,&b ) ;
    }
}rec[60] ;
const int L = 1e6 + 10 ;
int x[120],y[120] ;
int xx[L] , yy[L] ;
int G[240][240] ;
int n , ans , kx , ky , lenx , leny ;
const int dir[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1 } ;
void discrete()
{
    sort( x , x + kx ) ;
    sort( y , y + ky ) ;
    lenx = unique( x , x + kx ) - x ;
    leny = unique( y , y + ky ) - y ;
    for ( int i = 0 ; i < lenx ; i++ ) xx[x[i]] = 2 * i ;
    for ( int i = 0 ; i < leny ; i++ ) yy[y[i]] = 2 * i ;
    for ( int i = 0 ; i < n ; i++ ) {
        int x1 = xx[rec[i].l] ;
        int x2 = xx[rec[i].r] ;
        int y1 = yy[rec[i].t] ;
        int y2 = yy[rec[i].b] ;
        for ( int j = x1 ; j <= x2 ; j++ ) G[j][y1] = G[j][y2] = 1 ;
        for ( int j = y2 ; j <= y1 ; j++ ) G[x1][j] = G[x2][j] = 1 ;
    }
}

bool check( int i , int j )
{
    bool ok = ( i >= 1 && j >= 1 && i <= 2 * lenx - 2 && j <= 2 * leny - 2 ) ;
    return ok ;
}
void dfs( int i , int j ) 
{
    G[i][j] = 1 ;
    for ( int k = 0 ; k < 4 ; k++ ) {
        int tmpi = i + dir[k][0] ;
        int tmpj = j + dir[k][1] ;
        if ( check( tmpi , tmpj ) && !G[tmpi][tmpj] )
            dfs( tmpi , tmpj ) ;
    }
}
void find() {
    ans = 0 ;
    for ( int i = 0 ; i < ( lenx << 1 ) ; i++ ) {
        if ( !G[i][0] ) dfs( i , 0 ) ;
        int tmp = ( leny << 1 ) - 1 ;
        if ( !G[i][tmp] ) dfs( i , tmp ) ;
    }
    for ( int i = 0 ; i < ( leny << 1 ) ; i++ ) {
        if ( !G[0][i] ) dfs( 0 , i ) ;
        int tmp = ( lenx << 1 ) - 1 ;
        if ( !G[tmp][i] ) dfs( tmp , i ) ;
    }
    for ( int i = 0 ; i < ( lenx << 1 ) ; i++ ) {
        for ( int j = 0 ; j < ( leny << 1 ) ; j++ ) {
            if ( !G[i][j] ) ans++ , dfs( i , j ) ;
        }
    }
}
int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);
    while ( cin >> n && n ) {
        kx = 0 , ky = 0 ;
        cls( G ) ;
        for ( int i = 0 ; i < n ; i++ ) {
            rec[i].input() ;
            x[kx++] = rec[i].l ;
            x[kx++] = rec[i].r ;
            y[ky++] = rec[i].t ;
            y[ky++] = rec[i].b ;
        }
        discrete() ;
        find() ;
        cout << ans + 1 << endl ;
    }
    return 0;
}

D - Clock Hands

題意:

有一個時鐘,時針每 H 小時走一圈。
現在給你一個時刻,求該時刻之後最近的時刻 t ,在時刻 t ,秒針與分針的夾角等於秒針與時針的夾角。
時刻 t 的秒數用分數表示。

思路:

先吐槽一下,,時鐘的題目一般都是在紙上寫啊寫,推出個公式,然後照着公式A過去就行了,結果這題用了半小時推公式,寫代碼用了兩小時。。還是 too simple 啊。
設時鐘一週的角度爲 1,輸入時刻爲 h : m : s。

angs=s60angm=m60+s3600angh=hH+m60H+s3600H

設經過 t 秒後,秒針與分針的夾角等於秒針與時針的夾角,即
2angs=angm+angh

還有一種情況是分針在0右邊,時針在0左邊,起初秒針在0
左邊,過了幾秒後秒針過0,此時,相當於秒針角度減少了一週,所以要在原公式裏補上圈數k(k是整數):
 angs=angs+angtangmangs=angs+1angh2angs+1=angm+angh 2(angt+angs)+k=angm+angh

至於分數的處理可以用分數類來做,或者把上式代入來計算gcd:

(119H1)(s+t)=60(H+1)m+3600h3600Hk

代碼:

#include<bits/stdc++.h>
using namespace std;

int gcd( int a , int b ) {
    return b? gcd( b ,a % b ) : a ;
}
int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);
    int H , h , m , s ;
    while ( cin >> H >> h >> m >> s ) {
        if ( !H && !m && !h && !s ) break ;
        int tmp = 119*H - 1 ;
        //(119H-1)(s+t) = 60(1+H)m + 3600h - 3600Hk 
        int t = 60*(1+H)*m + 3600*h - 3600*H - tmp*s ;
        while ( t < 0 ) t += 3600*H ;
        int sec = 60 * s * tmp + 60 * t ;
        int min = 60 * m * tmp + sec / 60 ;
        int hour ;
        if ( sec == min ) t += 3600*H ;
        sec = s * tmp + t ;
        min = m + sec / ( tmp * 60 ) ;
        hour = h + min / 60  ;
        min %= 60 ; hour %= H ; sec %= tmp * 60 ;
        int d = gcd( sec , tmp ) ;
        printf( "%d %d %d %d\n" ,hour ,min ,sec/d ,tmp/d ) ;
    }
    return 0;
}

E - Dragon’s Cruller

思路:

題意略去。。
這題想通了其實挺簡單的,康拓展開+優先隊列+bfs。
把九宮格轉換成一行,那麼一個狀態就是一種排列,用康拓展開將排列映射到一個數字,然後搜索狀態直到符合所求狀態,用優先隊列維護花費。

代碼:

/*
Creat Time:2015/11/2 21:27:15
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<ctime>
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define pr( x ) cout << #x << " = " << x << endl 
#define pri( x ) cout << #x << " = " << x << " " 
#define test( t ) int t ; cin >> t ; int kase = 1 ; while( t-- )
#define out( kase ) printf( "Case %d: " , kase++ )
#define sqr( x ) ( x * x )
#define mp make_pair
#define pii pair<int,int>
#define fi fist
#define se second
#define pb push_back
using namespace std;
typedef long long lint;
const double eps = 1e-8 ;
const int inf = 0x3f3f3f3f ;
const long long INF = 0x3f3f3f3f3f3f3f3fLL ;

const int fac[10] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 } ;
const int N = 363000 ;
int ch , cv ;
int a[9] , b[9] , cost[N] ;
int fi , ed ;
bool vis[N] ;
struct Node{
    int x , w ; 
    Node( int _x , int _w ):x(_x) , w(_w) {} 
    bool operator < ( const Node &a )const {
        if ( w != a.w ) return w > a.w ;
        return x < a.x ;
    }
} ;
priority_queue<Node> q ;
int A2int( int *a , int n )
{
    int res = 0 ;
    for ( int i = 0 ; i < n ; i++ ) {
        int tmp = a[i] ;
        for ( int j = 0 ; j < i ; j++ ) {
            if ( a[j] < a[i] ) tmp-- ;
        }
        res += fac[n-1-i] * tmp ;
    }
    return res ;
}
void int2A( int x , int *a , int n )
{
    bool flag[10] ;
    int j ;
    cls( flag ) ;
    for ( int i = 0 ; i < n ; i++ ) {
        int tmp = x / fac[n-1-i] ;
        for ( j = 0 ; j < n ; j++ ) {
            if ( !flag[j] ) {
                if ( !tmp ) break ;
                tmp -- ;
            }
        }
        a[i] = j , flag[j] = 1 ;
        x %= fac[n-i-1] ;
    }
}
void update( int num , int cos )
{
    if ( !vis[num] && cos < cost[num] )
        cost[num] = cos, q.push( Node( num , cos ) ) ;
}
void bfs() 
{
    while ( !q.empty() ) {
        Node p = q.top() ; q.pop() ;
        if ( vis[p.x] ) continue ;
        vis[p.x] = true ;
        if ( p.x == ed ) {
            printf( "%d\n" , p.w ) ;
            break ;
        }
        int2A( p.x , a , 9 ) ;
        int k = 0 , tmp ;
        while ( a[k] > 0 ) k++ ;

        swap( a[k] , a[(k+1) % 9] ) ; //left
        tmp = A2int( a , 9 ) ;
        update( tmp , p.w + ch ) ;
        swap( a[k] , a[(k+1) % 9] ) ; 

        swap( a[k] , a[(k+8) % 9] ) ; //right
        tmp = A2int( a , 9 ) ;
        update( tmp , p.w + ch ) ;
        swap( a[k] , a[(k+8) % 9] ) ;

        swap( a[k] , a[(k+3) % 9] ) ; //up
        tmp = A2int( a , 9 ) ;
        update( tmp , p.w + cv ) ;
        swap( a[k] , a[(k+3) % 9] ) ; 

        swap( a[k] , a[(k+6) % 9] ) ; //down
        tmp = A2int( a , 9 ) ;
        update( tmp , p.w + cv ) ;
        swap( a[k] , a[(k+6) % 9] ) ; 
    }
}
int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);
    while ( ~scanf( "%d%d" ,&ch ,&cv ) ) {
        if ( !ch && !cv ) break ;
        for ( int i = 0 ; i < 9 ; i++ ) scanf( "%d" , a + i ) ;
        for ( int i = 0 ; i < 9 ; i++ ) scanf( "%d" , b + i ) ;
        fi = A2int( a , 9 ) ; ed = A2int( b , 9 ) ;
        cost[fi] = 0 ;
        while ( !q.empty() ) q.pop() ;
        cls( vis ) , clr( cost , inf ) ;
        q.push( Node( fi , 0 ) ) ;
        bfs() ;
    }
    return 0;
}

I - Hidden Tree

DP我只認狗哥!

發佈了127 篇原創文章 · 獲贊 14 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章