A题 CF22A Second Order Statistics
大水题:
找到数组中第二小的数,排个序找就好了,注意排完序之后要去重
比如 1 1 2 3,答案其实是第3个数
const int N = 110;
int n, a[N];
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a+1, a+1+n);
int f = a[1];
for(int i = 1; i <= n; i++)
{
if(a[i] != f)
{
cout << a[i] << endl;
return 0;
}
}
cout << "NO" << endl;
return 0;
}
B题 CF9A Die Roll
骰子能投出的分数范围是[1, 6],题目给出小Y和小W的分数,问小D获胜的概率:
另 K = max(小Y, 小D)
如果K == 1,那么小D是必胜的,因为就算小D的分数和K相同也算小D胜
如果K > 6 ,那么小D必败
当 1 < K <=6
计算小D获胜的概率,并化简!
int main()
{
int y, w;
cin >> y >> w;
int k =max(y, w);
if(k > 6) {
cout << "0/1" << endl; return 0; }
if(k == 1) {
cout << "1/1" << endl; return 0; }
int fz = 7 - k;
int g = __gcd(fz, 6); // __gcd 是C++库里的一个函数,可以直接用
cout << fz/g << "/" << 6/g << endl;
return 0;
}
C题 CF9C Hexadecimal’s Numbers
(这题挺恶心的,写了1个小时。。。。)
因为只能填0或1,可以先列一下前几个数
1,10,11,100,101,110,111……
不难发现它和二进制有着密切的关系
如果111是[1,n]范围内的一个合法数,那么它前面的几个1,10,11,100,101肯定也都可以,而从1~111是很好算的,我们只需要把他当作二进制来看就不难得出,这个个数就是111所代表的10进制数23-1 = 7
所以我们只需要找到[1,n]范围内最大的一个01串,然后把它当作2进制数,将它转换为10进制数后就是答案
int main()
{
int n; cin >> n;
int t = n, s = 0;
while(t) s++, t /= 10; //s是计算n有多少位
int res = 0;
int ten = 1;
for(int i = 1; i < s; i++) ten *= 10;
//我们规定个位是第0位,位数是[0,s-1]
for(int i = s-1; ~i; i--, ten /= 10)
{
int num = n / ten % 10; //得到n的第i位数
// cout << num << endl;
if(num > 1) {
res += pow(2, i+1)-1; break; }
//如果第i为大于2,那么后面的其他所有位都可以填1
//比如说10200,最大的是10111;
if(num == 1) res += pow(2, i);
//如果第i位为1,就填1,对答案的贡献为2^i
}
cout << res << endl;
return 0;
}
D题 CF8A Train and Peter
题目的意思是给定一个字符串s0,然后给2个子串s1,s2
问:
1、在s0中是否可以找到s1和s2,并且s2出现在s1之前?(因为s1是先看到的,s2是后看到的),如果可以,输出"forward"
2、然后反转s0,也就是把s0倒过来
然后在问是否可以在s0中找到s1和s2,并且s2出现在s1之前?如果可以,输出"backward"
3、如果两个都可以输出"both"
4、如果s1与s2不合法 或者 找不到这样的子串 就输出"fantasy"
来看看第4个情况如何确定:
首先,Peter中途睡着了,也就是说,他这两次不可能把所有的旗子都看到,所以,如果s1的长度+s2的长度大于s0的长度,那么该情况不合法
还有,如果在s0中找不到s1这样的子串或者s2这样的子串,也不合法
先介绍一个string类型自带的函数,比较方便,也可以自己写一个函数
find函数:
string a,b;
a.find(b) 是在a中查找b,如果找到了,返回b在a中第一次出现的位置,
没找到返回-1
a.find(b,k)是从a的下标为k的地方开始找b,找到了返回b在a中第一次出现的位置,没找到返回-1
int main()
{
string s0, s1, s2;
cin >> s0 >> s1 >> s2;
if(s1.length()+ s2.length() > s0.length())
{
cout << "fantasy" << endl; return 0;
}
bool f1 = 0, f2 = 0; //f1判断正着来是否成功,f2是倒着来
int p1 = s0.find(s1);
int p2 = s0.find(s2, p1 + 1);
// cout << p1 << " " << p2 << endl;
if(p1 <= p2) f1 = 1; //s1出现在s2之前
if(p1 == -1 || p2 == -1) f1 = 0; //没找到这样的子串
reverse(s0.begin(), s0.end()); //反转s0
p1 = s0.find(s1);
p2 = s0.find(s2, p1 + 1);
// cout << p1 << " " << p2 << endl;
if(p1 <= p2) f2 = 1;
if(p1 == -1 || p2 == -1) f2 = 0;
if(f1 && f2) cout << "both" << endl;
else if(f1) cout << "forward" << endl;
else if(f2) cout << "backward" << endl;
else cout << "fantasy" << endl;
return 0;
}
E题 CF9B Running Student
题目说的很清楚了,而且n比较小,直接枚举每一个站点,注意第一个站点不能当作下车的地方,然后按要求比较大小,留下符合要求的一个
int n;
double x[110], fx, fy, vb, vs;
double dis(int i) //计算站点i到(fx,fy)的距离
{
double dx = fx - x[i], dy = fy;
return sqrt(dx * dx + dy * dy);
}
double get(int i) //计算把i当作下车的站点花费的时间
{
double t1 = x[i] / vb;
double t2 = dis(i) / vs;
return t1 + t2;
}
int main()
{
cin >> n >> vb >> vs;
for(int i = 1; i <= n; i++) cin >> x[i];
cin >> fx >> fy;
double T = 1e18, d; //T保留的是最小时间,d是站点res到(fx,fy)的距离
int res;
for(int i = 2; i <= n; i++) //注意从第二个车站开始枚举
{
double t = get(i);
// cout << t << endl;
if(t < T)
res = i, T = t, d = dis(i);
else if(t == T && dis(i) < d)
res = i, d = dis(i);
}
cout << res << endl;
return 0;
}
F题 CF4C Registration system
这题可以用map来解决,非常方便
不熟悉map的可要好好学学
map<string,int> cnt; //cnt记录字符串出现的次数
int main()
{
int n; cin >> n;
string name;
while(n--)
{
cin >> name;
if(cnt[name] == 0) //如果name出现的次数为0,表明它是第一次出现
{
cout << "OK" << endl;
cnt[name]++; //次数+1
}
else
{
cout << name << cnt[name] << endl; //输出它是第几次出现
cnt[name]++; //次数+1
}
}
return 0;
}