近期训练汇总

TopCoder SRM 577 DIV1 B

题意:给你一个8*8的图,里面有一些#和.。现在要把所有的#都覆盖掉,第一次覆盖#的时候不需要花费,接下来每覆盖一个#,花费为该点与最远一个已经被覆盖的点的曼哈顿距离。

最后求最小的花费。

其实我们把这个问题倒着来看,当所有的点都被覆盖的时候,这时候,我们从后推回去。

那么最后一个被覆盖的点应该是哪个?

这时候我们就可以找出已经被覆盖的点中,距离最远的两个点,这两个点都可能是最后一个覆盖的点,所以就分别消掉这个点,递归下去。一直到只剩一个点,因为这个点是免费的。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
#define ull unsigned ll
using namespace std;
class EllysChessboard {
public :
    int minCost(vector <string> board) ;
    int dfs(ull st , int now ) ;
} ;

int dis[111][111] ;
map<ull , int >mm ;
int EllysChessboard :: dfs(ull st , int cnt) {
    if(cnt <= 1)return 0 ;
    if(mm.count(st) >= 1)return mm[st] ;
    int nowx = -1 , nowy = -1 ;
    int x = 0 ;
    for (int i = 0 ; i < 64 ; i ++ ) if(st >> i & 1)
            for (int j = i + 1 ; j < 64 ; j ++ )if(st >> j & 1)
                    if(dis[i][j] > x) {//找到距离最远的两个点。
                        x = dis[i][j] ;
                        nowx = i ;
                        nowy = j ;
                    }
    return mm[st] = min(dfs(st ^ (1ull << nowx) , cnt - 1) , dfs(st ^ (1ull << nowy) , cnt - 1)) + x ;//分别消去两个点,递归下去

}
int EllysChessboard ::minCost(vector <string> board) {
    int n = board.size() ;
    int m = board[0].size() ;
    for (int i = 0 ; i < n ; i ++ ) {
        for (int j = 0 ; j < m ; j ++ ) {
            for (int k1 = 0 ; k1 < n ; k1 ++ ) {
                for (int k2 = 0 ; k2 < m ; k2 ++ ) {
                    dis[i * 8 + j][k1 * 8 + k2] = abs(i - k1) + abs(j - k2) ;
                }
            }
        }
    }
    ull state = 0 ;
    int cnt = 0 ;
    for (int i = 0 ; i < n ; i ++ ) {
        for (int j = 0 ; j < m ; j ++ ) {
            if(board[i][j] == '#') {
                cnt ++ ;
                state |= 1ull << (i * 8 + j) ;
            }
        }
    }
    mm.clear() ;
    return dfs(state , cnt) ;
}
int main() {
    return 0 ;
}

TCHS SRM 46 DIV1

难道是我手贱选了一场DIV2?不然为什么他显示的是DIV1题却那么水。

A,水题,直接标记计数即可。

B,我没想到什么好方法,但是数据量才1000,我直接暴力枚举n - 1000的工人,然后这么多工人要弄到needFood所需要的时间,取最小值即可。

C,数据量小,直接BFS爆搜,有个TRICK就是,如果A是被B保护的,那么要先弄死B才去弄死A,然后就没什么了。

#line 5 "KingsTour.cpp"
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std ;
struct Point {
    int x , y ;
    Point() {}
    Point(int xx , int yy) : x (xx) , y(yy) {}
} s , s1 , s2 ;
int dis[11][11] ;
bool vis[11][11][3] ;
int dx[8] = {0 , 0 , 1 , -1 ,-1 , 1 , -1 , 1} ;
int dy[8] = {1 , -1, 0 , 0 ,-1 , -1 , 1 , 1 } ;
class KingsTour {
public:
    Point change(string x) ;
    int attackPawns(string king, string pawnA, string pawnB) {
        s = change(king) ;
        s1 = change(pawnA) ;
        s2 = change(pawnB) ;
        mem(vis ,0) ;
        vis[s1.x + 1][s1.y + 1][0] = 1 ;
        vis[s1.x + 1][s1.y - 1][0] = 1 ;
        vis[s1.x + 1][s1.y + 1][1] = 1 ;
        vis[s1.x + 1][s1.y - 1][1] = 1 ;
        vis[s2.x + 1][s2.y + 1][1] = 1 ;
        vis[s2.x + 1][s2.y - 1][1] = 1 ;
        gao() ;
        return dis[s1.x][s1.y] ;
    }
    void gao() ;
}  ;
Point KingsTour::change(string x) {
    int xx = x[1] - '0' ;
    int yy =  x[0] - 'a' + 1 ;
    return Point(xx , yy) ;
}
struct F {
    Point s ;
    int st ;
    F(Point x , int ss): s (x) , st(ss) {}
} ;
queue<F>qe ;
int check1(Point x) {
    return x.x == s1.x && x.y == s1.y ;
}
int inmap(int x ,int y) {
    return x >= 1 && x <= 8 && y >= 1 && y <= 8 ;
}
int check2(Point x) {
    return x.x == s2.x && x.y == s2.y ;
}
void relax(int tx , int ty , int x , int y  , int st) {
    if(dis[tx][ty] > dis[x][y] + 1) {
        dis[tx][ty] = dis[x][y] + 1 ;
        qe.push(F(Point(tx , ty) , st)) ;
    }
}
void show(Point x){
    cout << x.x << " " << x.y << " " << dis[x.x][x.y] << endl;
}
void  KingsTour::gao() {
    qe.push(F(s , 1)) ;
    for (int i = 0 ; i < 10 ; i ++ )
        for (int j = 0 ; j < 10 ; j ++ ) dis[i][j] = inf ;
    dis[s.x][s.y] = 0 ;
    while(!qe.empty()) {
        F tp = qe.front() ;
        qe.pop() ;
        show(tp.s) ;
        if(check1(tp.s))return ;
        for (int i = 0 ; i < 8 ; i ++ ) {
            int tx = tp.s.x + dx[i] ;
            int ty = tp.s.y + dy[i] ;
            if(inmap(tx , ty) && vis[tx][ty][tp.st] != 1) {
                Point now(tx ,ty) ;
                if(check1(now)) {
                    relax(tx , ty , tp.s.x , tp.s.y ,tp.st) ;
                    return ;
                }
                if(check2(now)) {
                    relax(tx , ty , tp.s.x , tp.s.y , 0) ;
                } else if(vis[tx][ty][tp.st] != 1) {
                    relax(tx , ty , tp.s.x , tp.s.y , tp.st) ;
                }
            }
        }
    }
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor

SRM 547 DIV1

A.简单求期望,给你两个柱子,相距W,然后第一个柱子的高度为1 到x中的一个数,第二个柱子的高度为1到y中的一个数。

问柱子顶部连一条绳子,这条绳的期望是多少。

因为x , y ,都是100W,那么暴力肯定不行,然后我就直接枚举两个柱子高度的差值,for : 1 , max(x , y ) - 1 。

对于每个高度的差值,可以求出他一共有多少种情况,然后直接加上去,最后ans / x / y 即可。复杂度是O(max(x , y)) .

SRM 546 DIV1 

B , 题意,给你一个D1 , C1 , D2 , C2 和一个N ,问大于等于N的一个数字里,最小的一个包含C1个D1,C2个D2的数字是多少。

比如 4 1 7 1 47 ,那么最小的就是47 。

这道题我是这么想的,首先我们求出这个N里面每一位上对应的数字,然后for 一下,对于每一位,我们取这一位+1,然后一直到9,这样我们取出来的数字就一定是大于N的。

然后我们找从这一位到最前面,有多少个数字是已经匹配上D1 , D2的,假设当前是第K位,那么对于K位以下,我们找出剩余的C1 , C2的个数,这里的数字需要放到0 - K - 1位这里,由于第K位总是大于当前位的,因为我们for的时候是+1的,所以我们只需要把剩余的0 ->K - 1位用0和D1 , D2代替掉,就可以了。

这里需要注意的就是,得特判如果一开始就是匹配的,比如上面给的那个样例,那么直接return N 就可以了。

int x[22] ;
long long FavouriteDigits::findNext(long long N, int digit1, int count1, int digit2, int count2) {
    ll nn = N ;
    mem(x , 0) ;
    if(count1 + count2 == 0)return N ;
    if(digit1 > digit2){
        swap(digit1 , digit2) ;
        swap(count1 , count2) ;
    }
    int num = 0 ;
    while(nn){
        x[num ++ ] = nn % 10 ;
        nn /= 10 ;
    }
    int c1 = count1 , c2 = count2 ;
    for (int i = 0 ; i < num ; i ++ ){
        if(x[i] == digit1)c1 -- ;
        else if(x[i] == digit2)c2 -- ;
    }
    c1 = c1 < 0 ? 0 : c1 ;
    c2 = c2 < 0 ? 0 : c2 ;
    if(c1 + c2 <= 0)return N ;
    for (int k = 0 ; ; k ++ ) {
        for (int d = x[k] + 1 ; d < 10 ; d ++ ){
            int now1 = count1 , now2 = count2 ;
            if(d == digit1) now1 -- ;
            if(d == digit2) now2 -- ;
            for (int c = k + 1 ; c < num ; c ++ ){
                if(x[c] == digit1)now1 -- ;
                else if(x[c] == digit2) now2 -- ;
            }
            now1 = now1 < 0 ? 0 : now1 ;
            now2 = now2 < 0 ? 0 : now2 ;
            if(now1 + now2 > k)continue ;
            ll ans = 0 ;
            for (int c = num - 1 ; c > k ; c -- ){
                ans = ans * 10 + x[c] ;
            }
            ans = ans * 10 + d ;
            for (int c = 0 ; c < k - now1 - now2 ; c ++ )ans *= 10 ;
            for (int c = 0 ; c < now1 ; c ++ )ans = ans * 10 + digit1 ;
            for (int c = 0 ; c < now2 ; c ++ )ans = ans * 10 + digit2 ;
            return ans ;
        }
    }
    return -1 ;
}

SRM 544 DIV1 

B , 题意,给你一幅图,每个格点都是0或者1,现在要你从左上角到右下角走一条最短路,然后这条最短路下面的格点的值全部取反,问最少需要走多少次最短路,才能使得整张图全变成0.

这道题我对着样例YY了一发,首先,我们要把每一行最右边的1变成0,然后我们每次都需要找到每一行最右边的1,但是需要注意的是,如果当前行i最右边的1是x , i + 1 ,行最右边的1是y,那么必须保证y >= x ,不然就不是最短路。然后把整张图更新掉,再判断一下是否是全为0。

复杂度,仔细观察一下图,我们可以得到一个结论,这个图上的任意一个1,都可以用2步把他变成0而不改变其他值。至于这个结论,想一下其实很简单,对于这个为1的格点,我们可以有2条最短路经过他,但是一条包括这个点,一条不包括,那么我们就可以把这个点变成0了。

所以对于50 * 50  的图,可以肯定他的复杂度在5000以内。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define SZ(x)  (int)((x).size())
const int maxint = -1u>>2 ;
const double eps = 1e-6 ;
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )

int Map[55][55] ;
class FlipGame {
public:
    int minOperations(vector <string> board);


};
int Y[55] ;
void find(int n , int m ){
    Y[0] = 0 ;
    for (int i = 0 ; i < n ; i ++ ){
        for (int j = m  ; j >= 1 ; j -- ){
            Y[i] = (i != 0 ? Y[i - 1] : 0) ;
            if(Map[i][j] == 1){
                Y[i] = max(Y[i] , j) ;break ;
            }
        }
    }
//    for (int i = 0 ; i < n ; i ++ ){
//        cout << Y[i] << endl ;
//    }
//    getchar() ;
//    for (int i = 0 ; i < n ; i ++ ){
//        for (int j = 1 ; j <= m ; j ++ ){
//            cout << Map[i][j] ;
//        }
//        cout << endl;
//    }
//    cout << endl ;
    for (int i = 0 ; i < n ; i ++ ){
        for (int j = 1 ; j <= Y[i] ; j ++ ){
            Map[i][j] = Map[i][j] ^ 1 ;
        }
    }
//    for (int i = 0 ; i < n ; i ++ ){
//        for (int j = 1 ; j <= m ; j ++ ){
//            cout << Map[i][j] ;
//        }
//        cout << endl;
//    }
}
int search(int n , int m){
    int sum = 0 ;
    for (int i = 0 ; i < n ; i ++ ){
        for (int j = 1 ; j <= m ; j ++ ){
            sum += Map[i][j] ;
        }
    }
    return sum != 0 ;
}
int FlipGame:: minOperations(vector <string> board) {
    int n = board.size() ;
    int m = board[0].size() ;
    for (int i = 0 ; i < n ; i ++ ){
        for (int j = 0 ; j < m ; j ++ ){
            Map[i][j + 1] = board[i][j] - '0';
        }
    }
    int ans = 0 ;
    while(search(n , m)){
        find(n , m) ;
        ans ++ ;
    }
    return ans ;
}



SRM 543 DIV1 

A。题意,给你两个数L , R , 计算从L ^ ....^R的值 ,^为异或。

找到每一位的1的个数就可以了。

我们列一下前10位的二进制数,找一下规律就可以了。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define SZ(x)  (int)((x).size())
const int maxint = -1u>>2 ;
const double eps = 1e-6 ;
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )


class EllysXors{
        public:
        long long getXor(long long L, long long R);


};
ll a[66] ;
ll sub[66] ;
void cal(ll *x , ll d){
    for (int i = 0 ; i < 55 ; i ++ ){
        ll fk = d ;
        fk -= sub[i] ;
        if(fk % a[i + 1] == 0){
            x[i] = fk / a[i + 1] * a[i] ;
        }
        else {
            x[i] = fk / a[i + 1] * a[i] ;
            ll now = fk % a[i + 1] ;
            if(now >= a[i])now = a[i] ;
            x[i] += now ;
        }

    }
}
ll a1[66] , a2[66] ;
long long EllysXors::getXor(long long L, long long R) {
    for (int i = 0 ; i < 60 ; i ++ )a[i] = 1ll << i ;
    sub[0] = 0 ;
    for (int i = 1 ; i < 60 ; i ++ )sub[i] = sub[i - 1] + a[i - 1] ;
    mem(a1 , 0) ; mem(a2 , 0) ;cal(a2 , R) ;
    cal(a1 , L - 1) ;
    for (int i = 0 ; i < 55 ; i ++ ){
        if(a1[i] >= 0 && a2[i] >= 0){
            a2[i] -= a1[i] ;
        }
    }
    ll ans = 0 ;
    for (int i = 0 ; i < 55 ; i ++ ){
        if((a2[i] & 1) && a2[i] > 0){
            ans += 1ll << i ;
        }
    }
    return ans ;
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor

B。给你N+1个小岛,每个小岛中间有条河。宽度为W,速度为S。

每个小岛的长度为L。还有这个人的速度walk,这个速度只能在岛上走,在河里的时候只能是水的速度。

问从第一个小岛的左下角走到第N+1个小岛的右上角最少需要多少时间。

首先,数据量,N = 50 , L = 100000 ,那么dp[i][j] 表示第J和小岛的第i个位置的最少时间。

那么转移方程很简单,dp[i][j] = min(dp[i][j] , dp[k][j - 1] + dis(i , k) / speed[j - 1]) 。k = 0...L。

那么显然如果直接递推是超时的。

这时候我们注意到,这可以用斜率优化来搞。

推出来公式很简单,左边是(dp[k][j - 1] - dp[l][j - 1] ) / (dis(i , l) - dis(i , k)) < 1 / speed[j - 1]。

那么就可以降一维了,复杂度大约是500W,但是需要注意的是我们的dp[i][j],不一定是从状态J - 1过来的,也可以从当前小岛的不同位置过来,但是其实我们可以忽略掉。但是我们直接从前一状态过来的当前位置代替即可,仔细想一下就知道了。

要锁门了,先贴代码。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define SZ(x)  (int)((x).size())
const int maxint = -1u>>2 ;
const double eps = 1e-6 ;
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x2fffffffffffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )


class EllysRivers {
public:
    double getMin(int length, int walk, vector <int> width, vector <int> speed);


};
#define N 111111
double dp[N][55] ;
int qe[N] ;
double getU(int j , int k , int l) {
    return dp[k][j - 1] - dp[l][j - 1] ;
}
double dis(int x , int y) {
    return sqrt(1.0 * x * x + 1.0 * y * y) ;
}
double getD(int i , int k , int l , int w) {
    return dis(abs(i - l), w) - dis(abs(i - k) , w) ;
}
double EllysRivers::getMin(int length, int walk, vector <int> width, vector <int> speed) {
    int n = width.size() ;
    for (int i = 0 ; i <= length ; i ++ ) {
        for (int j = 0 ; j <= n ; j ++ ) {
            dp[i][j] = inf ;
        }
    }
    for (int i = 0 ; i <= length ; i ++ ) {
        dp[i][0] = i * 1.0 / walk ;
    }
    for (int j = 1 ; j <= n ; j ++ ) {
//        if(walk >= speed[j - 1]) {
            for (int i = 0 ; i <= length ; i ++ ) {
                dp[i][j] = min(dp[i][j - 1] + dis(width[j - 1] , 0) / speed[j - 1] , dp[i][j]) ;

            }
//            for (int i = 0 ; i < length ; i ++ ) {
//                for (int xx = -10 ; xx <= 10 ; xx ++ ) {
//                    int y = max(0 , xx + i) ;
//                    y = min(length , y) ;
//                    dp[i][j] = min(dp[y][j] + abs(y - i) * 1./ walk , dp[i][j]) ;
//                }
//            }
//        }
        int l = 0 , r = 0 ;
        qe[r ++ ] = 0 ;
        for (int i = 0 ; i <= length ; i ++ ) {
            while(l + 1 < r && getU(j , qe[l + 1] , qe[l]) <=
                    getD(i , qe[l + 1] , qe[l] , width[j - 1]) / speed[j - 1]) l ++ ;

            dp[i][j] = min(dp[qe[l]][j - 1] + dis(abs(qe[l] - i) , width[j - 1]) / speed[j - 1] , dp[i][j]) ;

            while(l + 1 < r && getU(j , i , qe[r - 1]) * getD(i , qe[r - 1] , qe[r - 2] , width[j - 1]) <=
                    getU(j , qe[r - 1] , qe[r - 2]) * getD(i , i , qe[r - 1] , width[j - 1]))r -- ;
            qe[r ++ ] = i ;
        }
//        for (int i = 0 ; i <= length ; i ++ ) {
//                for (int xx = -10 ; xx <= 10 ; xx ++ ) {
//                    int y = max(0 , xx + i) ;
//                    y = min(length , y) ;
//                    dp[i][j] = min(dp[y][j] + abs(y - i) * 1./ walk , dp[i][j]) ;
//                }
//            }
    }
    //{42, 337, {1, 1, 1}, {1, 1, 1}}
    //{1, 1, {1, 1, 1}, {1000000, 1, 1}}
//    printf("%.20f\n",dp[length][n]) ;
    return dp[length][n] ;
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor


SRM 571 DIV1

A,题意,给你一个N,如果N小于等于50,叫你将N按字典序排序然后输出,如果N大于50,那么输出字典序最小的50个数字。

思路:对于小于等于50的数字,我把所有的数字都搞出来排序输出。

对于大于50的数字,我求出他有多少位,然后按位来搞,每一位取前100个数字,那么最多取1000个数字,然后排序输出前50个即可。

算法的正确性很好验证,就不多说了。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define SZ(x)  (int)((x).size())
const int maxint = -1u>>2 ;
const double eps = 1e-6 ;
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )


class FoxAndMp3{
        public:
        vector <string> playList(int n);


};
#define N 5555
string a[N] ;
string get(int x){
    string now = "" ;
    while(x){
        now += char(x % 10 + '0') ;
        x /= 10 ;
    }
    reverse(now.begin() , now.end()) ;
    return now + ".mp3" ;
}
int sz(int x){
    int now = 0 ;while(x){now ++ , x /= 10 ;} return now ;
}
vector<string> ans ;
ll ss[11] = {0 , 1, 10 , 100 , 1000 , 10000 , 100000 , 1000000 , 10000000 , 100000000 ,1000000000ll } ;
vector <string> FoxAndMp3:: playList(int n) {
    if(n <= 50){
        for (int i = 1 ; i <= n ; i ++ ){
            a[i] = get(i) ;
        }
        sort(a + 1 , a + n + 1) ;
        for (int i = 1 ; i <= n ; i ++ ){
            ans.push_back(a[i]) ;
        }
        return ans ;
    }
    else {
        int d = 0 ;
        int l = sz(n) ;
        for (int i = 1 ; i <= l ; i ++ ){
            for (int j = ss[i] ; j < ss[i + 1] && j <= n && j <= ss[i] + 100 ; j ++ ){
                a[d ++ ] = get(j) ;
            }
        }
        sort(a , a + d ) ;
        for (int i = 0 ; i < 50 ; i ++ )ans.push_back(a[i]) ;
        return ans ;
    }
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor


SRM574 div1.

A.给你2个数,A,B。有2个操作,一个是反转一个数,一个是对一个数除以10,整数除法。

然后问A是否可以在某一步等于B。

乍一看以为是博弈。但是仔细一想,第二个数我们可以不用考虑他的操作。

因为假设B进行某一个操作之后使得A和他相同了,那么B一定不会进行那个操作,所以B一定是维持原来的样子。不会进行除法。

所以这个问题就简化成了,对A进行一次深搜,找出他所有操作的情况,然后看是否包含B,和B的反转数。

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define SZ(x)  (int)((x).size())
const int maxint = -1u>>2 ;
const double eps = 1e-6 ;
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )


class TheNumberGame{
        public:
        string determineOutcome(int A, int B);
};
set<int>F ;
int a[20] ;
int rev(int x){
    int l = 0 ;
    while(x){
        a[l ++ ] = x % 10 ;
        x /= 10 ;
    }
    int y = 0 ;
    for (int i = 0 ; i < l ; i ++ )
        y = y * 10 + a[i] ;
    return y ;
}
void dfs(int A , bool isrev){
    if(A == 0){
        F.insert(A) ;
        return ;
    }
    F.insert(A) ;
    dfs(A / 10 , 0) ;
    if(!isrev){
        int B = rev(A) ;
        dfs(B , 1) ;
    }
}
string TheNumberGame:: determineOutcome(int A, int B) {
    F.clear() ;
    dfs(A , 0) ;
    int revB = rev(B) ;
    set<int>::iterator it ;bool ok = 0 ;
    for (it = F.begin() ; it != F.end() ; it ++ ){
        if(*it == B || *it == revB){
            ok = 1 ;break ;
        }
    }
    if(ok)return "Manao wins" ;
    else return "Manao loses" ;
}
// BEGIN CUT HERE
int main(){
        TheNumberGame ___test;
        ___test.run_test(-1);
        return 0;
}
// END CUT HERE


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值