F H I 都是字符串的大水题,就看谁的手速快,题目描述多,但是看样例就很容易明白。
去年打天梯赛前对stringstream了解了一下,还不错,这场比赛用到了几次,减少了不少的代码量。
A - All about that base
题目大意:简单来说就是问一个等式在1-36进制中,哪个进制可以成立,一个都没有的话就输出 ”invalid“。然后10-35进制是用a-z表示,36进制是用0表示。
分析:题目给出的范围描述是所有的数在10进制下都是不超过long long级别的。所以我们就可以直接暴力判断1-36进制,可以先把当前的进制数用10进制表示,再看等式是否成立。注意题目说:在1进制的时候,只能有数字0,并且用数字1代表数字0。这个会wa在第4个样例。
算是个大模拟,过程比较繁琐。多写多用一下函数,可以少一下代码量,也更加清晰。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ch(char c) //小写字母转换成10进制数字
{
ll ans;
if (c >= 'a' && c <= 'z') ans = c - 'a' + 10;
else ans = c - '0';
return ans;
}
ll to(string s, ll q)//q进制转化成10进制的数
{
ll ans = 0;
ll n = s.size();
for (ll i = 0; i < n; i++)
{
ll x = ch(s[i]);
ans += x * pow(q, n - i - 1);
}
return ans;
}
bool f(string x, string y, string z, ll q, string op)
{
ll xx = to(x, q);//获得当前进制下的10进制的值
ll yy = to(y, q);
ll zz = to(z, q);
if (op == "+")
return xx + yy == zz;
else if (op == "-")
return xx - yy == zz;
else if (op == "*")
return xx * yy == zz;
else if (op == "/")//除法要用上强制转换
return (double)xx / (double)yy == (double) zz;
}
ll pan(string s) //找到最小进制的函数
{
ll res = 0;
ll n = s.size();
for (ll i = 0; i < n; i++)
{
ll x = ch(s[i]);
res = max(res, x);
}
return res;
}
bool pan1(string s) //在特判1进制的时候,看有没有数字0
{
ll n = s.size();
for (ll i = 0; i < n; i++)
{
ll x = ch(s[i]);
if (x == 0) return false;
}
return true;
}
void solve()
{
ll flag = 0;
string x, y, z, op1, op2;//输入等式。
cin >> x;
cin >> op1;
cin >> y;
cin >> op2;
cin >> z;
ll ma = 0;//判断一下可能正确的最小的进制,当等式中有9时,最小的进制只能是10,9以下的进制不可能出现数字9
ma = max(ma, pan(x));
ma = max(ma, pan(y));
ma = max(ma, pan(z));
if (ma == 1)//特判一下1进制
{
if (pan1(x) && pan1(y) && pan1(z)) ma = 0;
else ma = 1;
}
for (ll i = ma + 1; i <= 36; i++)//暴力判断1-36进制
{
if (f(x, y, z, i, op1))
{
if (i <= 9) cout << i;
else if (i == 36) cout << 0;
else cout << (char)(i + 'a' - 10);
flag = 1;
}
}
if (flag == 0) cout << "invalid";
cout << endl;
}
int main()
{
ll t;
cin >> t;
while (t--) solve();
return 0;
}
B - Bobby’s Bet
题目大意:投掷一个S面的骰子,若能够在Y次以内掷出 >= X次面值 >= R,则可以获得W倍的赌注,但你不喜欢冒险,判断期望回报是否大于原赌注,如果大于,这场bet可以进行,反之,不可以。
分析:就是一道概率期望题,说是高中的数学题也不为过,首先在Y场中先选出k场比赛(k>=x),这k场比赛可以投掷出面值 >= R,其他Y-k场不能投掷出。而投掷出面值 >= R的概率是(S - R + 1) / S。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50;
int c[N][N];
void get_c(int n) //先计算出可能用到的组合数,以防超时
{
for (int i = 1; i <= n; i++)
{
c[i][0] = 1;
for (int j = 1; j <= i; j++)
{
c[i][j] = c[i][j - 1] * (i - j + 1) / j;
}
}
}
void solve()
{
int r, s, x, y, w;
cin >> r >> s >> x >> y >> w;
double p = (double)(s - r + 1) / s * 1.0;
double ans = 0;
for (int i = x; i <= y; i++)
{
ans += pow(p, i) * pow(1 - p, y - i) * c[y][i];
}
if (w * ans > 1) cout << "yes" << endl;
else cout << "no" << endl;
}
int main()
{
get_c(20);
ll t;
cin >> t;
while (t--) solve();
return 0;
}
J - Torn To Pieces
题目大意:有n个站点,给出每个站点的连接情况,询问能否从一个起点走到终点,可以的话打印出从起点到终点的一条路径,否则,打印“no route found”。题目保证只有一种路径。
分析:很容易想出来是一个普通的dfs+打印路径,因为题目给出的站点都是字符串类型,所以我们需要把每个站点进行编号后,再存入。然后就是dfs找的时候可以从终点到起点找,方便打印路径。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50;
int start, endd;
map<string, int>mp;
map<int, string>mm;
map<int, int>q[N];
int flag = 0;
map<int, int>v[N];
void dfs(int st)
{
for (int i = 0; i < q[st].size(); i++)//遍历与当前站点相连的站点
{
int tt = q[st][i];
if (v[st][tt] == 1) continue;//避免死循环
v[st][tt] = 1;
v[tt][st] = 1;
if (tt == start)//找到起点就输出并且记录已找到
{
flag = 1;
cout << mm[tt];
return ;
}
dfs(tt);//否则就继续dfs
if (flag == 1)//上方的dfs中找到路径,说明当前站点是必经之路,打印
{
cout << " " << mm[tt];
return ;
}
}
}
int main()
{
int n, cnt = 1;
cin >> n;
for (int i = 0; i < n; i++)
{
string s, t;
string sta;
cin >> sta;
if (mp[sta] == 0)//对新的站点进行编号
mp[sta] = cnt, mm[cnt++] = sta;
int sta1 = mp[sta];
getline(cin, s);
stringstream ss(s);
while (ss >> t)
{
if (mp[t] == 0)//对新的站点进行编号
mp[t] = cnt, mm[cnt++] = t;
q[sta1][q[sta1].size()] = mp[t];
q[mp[t]][q[mp[t]].size()] = sta1;
}
}
string Start, Endd;
cin >> Start >> Endd;
start = mp[Start];
endd = mp[Endd];
dfs(endd);//从终点到起点找
if (flag == 0) cout << "no route found";
else cout << " " << mm[endd];//打印终点
cout << endl;
return 0;
}