转义字符
A. 转义字符
按顺序扫一遍读到的字符串,碰到了反斜杆就把后三个字符取出来做下进制转换再输出。
int main(){
char s[500];
while (scanf("%s", s), strcmp(s, "end") != 0){
for (int i=0; s[i]!=0; i++)
if (s[i] == '\\'){
int t = 0;
for (int j=0; j<3; j++)
t = t * 8 + s[++i] - '0';
putchar(t);
} else putchar(s[i]);
printf("\n");
}
return 0;
}
B. 猫抓老鼠
这一题的结论就是:当猫的速度小于等于老鼠速度4倍时,老鼠有策略肯定能逃脱,否则可以证明无论如何也无法逃脱。
存在一个池塘边缘的同心圆,老鼠在这个圆上跑的角速度与猫在池塘边缘跑的角速度一样,可以称这个圆为内圆。在内圆内部,老鼠总是可以得到比猫更大的角速度,所以在内圆内部,老鼠可以时刻保持他与猫的连线经过圆心。因此,老鼠的逃跑策略可以分成两个阶段:第一阶段的目的是拉开距离:在保持自己与猫的连线经过圆心的前提下,尽可能远离猫,这一阶段老鼠与猫的距离可以无限接近小圆半径加池塘半径;第二阶段的目的是上岸:这一阶段老鼠的最佳策略是朝着离岸最近的点游。
设按这种策略,猫正好在老鼠上岸的那一刻与老鼠相遇,猫的速度是V。可以算出V为4到5之间的实数,所以有上面的结论。
C. 通往女友之路
这一题的关键就是算出坐出租车的话,最少需要的时间。如果坐出租车,这一题实际上可以转换为光的折射模型:入射角与出射角的正弦之比等于光在两种介质中的速度之比。即,若设坐出租车的地方在p=(x,0)处最佳,则 mm
(|x-x|/|p-p|)/(|x-x|/|p-p|)=v/v m1m1m2m2rt
, (|x-x|*|p-p|)/(|x-x|*|p-p|)=v/v m1m2m2m1rt
, |x-x|*|p-p|*v=|x-x|*|p-p|*v m1m2tm2m1r
x可以用二分法来求。对于任意的p=(x,0),满足min(x, x) < x < max(x, x), m1212当|x-x|<|x-x|时,显然|x-x|*|p-p|*v<|x-x|*|p-p|*v 1m112t21r
当|x-x|>|x-x|时,显然|x-x|*|p-p|*v<|x-x|*|p-p|*v 1m112t21r
此外,因为随着上车点p=(x,0)在min(x, x)到max(x, x)间单调变化,总共要花的时间一定1212
是先单调递减到最小值后再单调递增,既是个单峰函数,所以可以用三分法: 若要求函数在(x,x)定义域内的最小值,且x
f(x)时,可以缩小定义域至(x,x),否则可以缩小定义域至(x,x)。 m1m2m121m2
D. 拱猪
模拟题,特别要注意的就是分牌的概念:虽然红桃2、3、4都是0分,但也都算是分牌,所
以在算变压器的带来的得分、收全红、和猪羊满圈时都要考虑。
E. Dota英雄传之等级炮
递推问题。
令f(n,pc)表示1…n中有多少个不包含p、p、…、p之外的质因子的数的个数,则 01pc-123f(n,pc) = f(n, pc-1) + f(n/p, pc-1) + f(n/p, pc-1) + f(n/p, pc-1) + …… pc-1pc-1pc-1当n=0时,
f(n,pc)=0
当n>0而pc=0时,
f(n,pc)=1
可以用递归来实现f。
long long below(long long n, const int *p, const int pn){
if (n == 0) return 0;
if (pn == 0) return 1;
long long count = 0;
while (n) {
count += below(n, p, pn-1);
n /= p[pn-1];
}
return count;
}
int main(){
int p[100], pn, a, b;
while (cin >> pn && pn){
for (int i=0; i> p[i];
sort(p, p+pn);
cin >> a >> b;
cout << below(b, p, pn) - below(a-1, p, pn) <说明一个是另一个循环右移后的结果,否则不是。
例如dabcabcd和cabcddab。将第一个串复制一遍得到dabcabcddabcabcd,可以发现第二个串是这个串的子串dabcabcddabcabcd。
对于这个问题,如果第一刀切的位置总是一样,那么实际上就是上面提到的问题,只不过串中的元素从一个字符变成了一列字符而已。由于图像的高度最多才10,所以只要枚举一下第一刀切的位置,就可以用上面的方法解了。
int main(){
int n, m;
while (scanf("%d %d", &n, &m), n && m){
int showcount[26];
memset(showcount, 0, sizeof(showcount));
// 准备第一个串
memset(s, 0, sizeof(s));
for (int i=0; i
方案 ,一定可以得到一个实际的游戏时间,那么再扫描一遍所有的非黑盒子,就可以得到一个这种黑盒处理方案下的最高得分。
n/100所有黑盒处理方案一共2个,扫描一遍所有的非黑盒子的时间复杂度为O(n),所以总的
n/100时间复杂度为O(n*2)。
要注意的一点就是:可能打开一个黑盒子后游戏时间减得很少以至于直接游戏结束,但是实际的游戏时间却应该到打开这个黑盒子的那一刻。
H. 取石子游戏
这一题是一个动态规划问题。
首先,每一轮结束的时候,两个人到达的格子一定在同一条斜线上,若设左下角为0行0列,则每条斜线上行号与列号之和一定相等。
因此想到用这样的坐标法来描述一个格子:(a,b)对应b行a-b列的那一格。 用f(k,i,j)表示先手在(k,i),后手在(k,j),两个人从这样的位置开始游戏,两人均采取最优策
略,最后的得分差。那么
f(k,i,j)=max(min(f(k+1,i+1,j), f(k+1,i+1,j+1)), min(f(k+1,i,j), f(k+1,i,j+1)) 其思路是:若先手从(k,i)走到(k+1,i+1),后手有两个选择,走到(k+1,j)或(k+1,j+1),对于后手,他肯定选对他来说更优的,也就是f(k+1,i+1,j)和f(k+1,i+1,j+1)中的较小值。即先手若走到(k+1,i+1),则其最后的得分肯定就是min(f(k+1,i+1,j), f(k+1,i+1,j+1))。同理可得,先手若走到(k+1,i),则其最后的得分肯定就是min(f(k+1,i,j), f(k+1,i,j+1)),作为先后,他肯定会选较大的那一个,所以有上面的递推式。
(k,i)和(k,j)可能不存在(不在有效棋盘上面),在实际编程时还有很多处理。
const int toosmall = -99999999;
#define goodplace(h, l) ((l)>=0 && (l)
=0 && (h)-(l)> n && n){
for (int i=n-1; i>=0; i--)
for (int j=0; j> map[i][j];
static int f[2][110][110];
f[0][n-1][n-1] = map[n-1][n-1];
for (int h=(n-1)*2-1; h>=0; h--){
for (int lf=0; lf