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