DIV 1
500ptr StrongEconomy
你有n个工厂和k个专家,增加一个工厂或专家需要花费price,每时刻会增加n*k,求达到target的最短时间。
思路:
1)晚买不如果早买。
2)让n与k尽量接近。
分析可知,我们不应按时间模拟,而应按购买过程模拟。由target <= 10^12。可知在2*10^6内可出解。
注意初始情况下,有可能n*k越界,加个特判。
class StrongEconomy {
public:
long long earn(long long n, long long m, long long p, long long t) {
if (t/n < m) return 1;
long long time = 0, cur = 0, s = n*m, ret = (t+s-1)/s, d;
while (s <= t) {
ret = min(ret, time+(t-cur+s-1)/s);
if (cur < p) {
d = (p-cur+s-1)/s;
time += d;
cur += d*s;
}
cur -= p;
n < m ? n++ : m++;
s = n*m;
}
return min(ret, time+1);
}
};
1000ptr RowGame
不会。。。
DIV 2
500ptr OrderedNim
在nim博弈的基础上,只有前面各堆均取完时,才能取此堆。
思路:实际上是限制了nim必须从左向右进行。
1)从右向左推(由终点向起点推),如果该堆为1,别无选择,win = !win;如果该堆>1,win = 1。
class OrderedNim {
public:
string winner(vector <int> a) {
bool win = 0;
for (int i = a.size()-1; i >= 0; i--)
if (a[i] > 1) win = 1;
else win = !win;
return win ? "Alice" : "Bob";
}
};
2)从左向右推(由起点向终点推),如果该堆为1,别无选择,win = !win;如果该堆>1,胜负已定,跳出。
class OrderedNim {
public:
string winner(vector <int> a) {
bool win = 0;
for (int i = 0; i < a.size(); i++) {
win = !win;
if (a[i] > 1)
break;
}
return win ? "Alice" : "Bob";
}
};
1000ptr EnemyTowers
把myUnits个生命值为1的士兵,分成两份去攻击生命值为hpT,攻击力为attackT的numWodT个木塔和numStoT个石塔。每轮由我方先攻击,求最少多少轮消灭敌人,无解返回-1。
思路:
1)人员分配可二分。
2)time(myUnits, hpT, attackT, numT)计算用myUnits个士兵打numT个塔所需时间。
显然,我们应当采取逐个消灭的策略。因此,记录塔的总生命值为total,则当前剩余的塔数为ceil(total/hp)。模拟即可。
#define INF 1000000000
int time(int n, int hp, int k, int t)
{
int total = hp*t, ret = 0;
while (n > 0 && total > 0) {
ret++;
total -= n;
n -= (total+hp-1)/hp*k;
}
if (total <= 0) return ret;
return INF;
}
class EnemyTowers {
public:
int attack(int n, int hp, int k, int wd, int st) {
int l = 0, r = n;
while (r-l > 1) {
int mid = (l+r)>>1;
if (time(mid, hp, k, wd) < time(n-mid, hp, k, st))
r = mid;
else
l = mid;
}
int ret = min(max(time(l, hp, k, wd), time(n-l, hp, k, st)), max(time(r, hp, k, wd), time(n-r, hp, k, st)));
return ret == INF ? -1 : ret;
}
};

浙公网安备 33010602011771号