SRM 548 DIV2

本来早就该写的,一直拖到现在。

第一题应该算是很水的题,就是数字的种类乘以某种数字出现的最大次数。

http://community.topcoder.com/stat?c=problem_solution&rm=313611&rd=15170&pm=11985&cr=23038076

第二题比赛期间没有想到,后来看来一下别人的,原来用二分法就可以搞定了

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <cstdlib>
 5 #include <map>
 6 #include <algorithm>
 7 #include <cmath>
 8 using namespace std;
 9 class KingdomAndTrees{
10 public:
11     bool valid(vector <int> heights,int l,int n){
12         heights[0]=max(heights[0]-l,1);
13         for(int i=1;i<n;i++){
14             if(heights[i]<=heights[i-1])
15                 heights[i]=min(heights[i-1]+1,heights[i]+l);
16             else
17                 heights[i]=max(heights[i-1]+1,heights[i]-l);
18 
19             if(heights[i]<=heights[i-1])
20                 return false;
21         }
22         return true;
23 
24     }
25     int minLevel(vector <int> heights){
26         int left=0;
27         int right=1000000000;
28         int mid;
29         int n=heights.size();
30         int exists=0;
31         while(left<right){
32             mid=(left+right)/2;
33             if(valid(heights,mid,n)){
34                 right=mid;
35                 exists=1;
36             }else{
37                 left=mid+1;
38             }
39         }
40 
41         return left;
42     }
43 };

第三题则悲催了,用的穷举法加剪枝,明显不行,第五个测试用例就超时了,就没有提交,据说是用的DFS,还没有看大牛的代码。

topcoder wiki 的答案,加上了自己的一点注释,自己真心想不出来啊.....

  1 #define FOR(x,a,b) for (int x = a; x <= b; x++)
  2 int f[(1 << 17) + 10][18][2];
  3 int n, cs[17], res[17], old[17];
  4 vector<int> rt;
  5 
  6 //s store information about wich digits is used
  7 //i is the position that we have to dicide which digits to push in
  8 //ok = 1 min the i + 1 digits prefix of the password is strictly less than the 
  9 //i + 1 digits prefix of oldpassword
 10 //f[s][i][ok] = 1 mean we can continue bulding the password that strictly less than oldpassword
 11 int lower(int s, int i, int ok) {
 12     if (f[s][i][ok] != -1)//假如已经计算出来了
 13         return f[s][i][ok];
 14     if (i == n) {
 15         f[s][i][ok] = ok;//备忘录
 16         return ok;
 17     }
 18 
 19     f[s][i][ok] = 0;
 20     FORD(j, n - 1, 0)//因为是选取小于原数字的最大值,所以倒着选
 21     if ((s & (1 << j)) == 0 //第j位还没有使用
 22             && cs[j] != rt[i]//不是限制的数字
 23             && (ok == 1 || cs[j] <= old[i]))//已经严格小或者当前位<=原来的
 24         if (lower(s | (1 << j),//使用第j位 
 25                 i + 1, //计算后边的
 26                 ok | (cs[j] < old[i]))) //填加第j位后是否<原来的
 27         {
 28             f[s][i][ok] = 1;
 29             return 1;
 30         }
 31 
 32     return 0;
 33 }
 34 
 35 //find the maximum password in all passwords that less than oldpassword
 36 void find_lower(int s, int i, int ok) {
 37     if (i == n)
 38         return;
 39 
 40     FORD(j, n - 1, 0)
 41     if ((s & (1 << j)) == 0 &&//某一位还没有选
 42             cs[j] != rt[i] &&//不是限制条件
 43             (ok == 1 || cs[j] <= old[i]))//判断是否可以用这个数字
 44         if (lower(s | (1 << j), i + 1, ok | (cs[j] < old[i]))) {
 45             res[i] = cs[j];
 46             find_lower(s | (1 << j), i + 1, ok | (cs[j] < old[i]));
 47             return;
 48         }
 49 }
 50 
 51 //funtion upper and find_upper is similar with lower and find_lower
 52 int upper(int s, int i, int ok) {
 53     if (f[s][i][ok] != -1)
 54         return f[s][i][ok];
 55     if (i == n) {
 56         f[s][i][ok] = ok;
 57         return ok;
 58     }
 59 
 60     f[s][i][ok] = 0;
 61     FOR (j, 0, n - 1)
 62         if ((s & (1 << j)) == 0 && cs[j] != rt[i]
 63                 && (ok == 1 || cs[j] >= old[i]))
 64             if (upper(s | (1 << j), i + 1, ok | (cs[j] > old[i]))) {
 65                 f[s][i][ok] = 1;
 66                 return 1;
 67             }
 68     return 0;
 69 }
 70 
 71 void find_upper(int s, int i, int ok) {
 72     if (i == n)
 73         return;
 74 
 75     FOR (j, 0, n - 1)
 76         if ((s & (1 << j)) == 0 && cs[j] != rt[i]
 77                 && (ok == 1 || cs[j] >= old[i]))
 78             if (upper(s | (1 << j), i + 1, ok | (cs[j] > old[i]))) {
 79                 res[i] = cs[j];
 80                 find_upper(s | (1 << j), i + 1, ok | (cs[j] > old[i]));
 81                 return;
 82             }
 83 }
 84 
 85 long long newPassword(long long oldPassword, vector<int> restrictedDigits) {
 86     n = 0;
 87     LL tg = oldPassword;
 88     while (tg) {
 89         cs[n++] = tg % 10;
 90         tg /= 10;
 91     }
 92 
 93     //old store digits of oldPassword from left to right
 94     //cs store digits of oldPassword in non-decrease order 
 95     FOR (i, 0, n - 1)
 96         old[i] = cs[n - 1 - i];
 97     sort(cs, cs + n);
 98 
 99     rt = restrictedDigits;
100     //FOR (i, 0, n - 1) cout << old[i] << " " << cs[i] << " " << rt[i] << endl;
101 
102     //if the new password can be same as the old one, return it
103     int ok = 1;
104     FOR (i, 0, n - 1)
105         if (old[i] == rt[i])
106             ok = 0;
107     if (ok)
108         return oldPassword;
109 
110     LL a, b;
111     a = b = -1;
112 
113     //find a is the maximum password that less than the oldPassword
114     SET(f, -1);
115     if (lower(0, 0, 0)) {
116         find_lower(0, 0, 0);
117         a = 0;
118         FOR (i, 0, n - 1)
119             a = a * 10 + res[i];
120     }
121 
122     //find b is the minimum password that greater than the oldPassword
123     SET(f, -1);
124     if (upper(0, 0, 0)) {
125         find_upper(0, 0, 0);
126         b = 0;
127         FOR (i, 0, n - 1)
128             b = b * 10 + res[i];
129     }
130 
131     //decide a or b is the result
132     if (a == -1)
133         return b;
134     if (b == -1)
135         return a;
136 
137     if (abs(a - oldPassword) > abs(b - oldPassword))
138         return b;
139     if (abs(a - oldPassword) < abs(b - oldPassword))
140         return a;
141 
142     return a;
143 
144 }
原文地址:https://www.cnblogs.com/kakamilan/p/2580201.html