2020ICPC上海(部分题解)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2020ICPC上海(部分题解)
G
(签到思维题)
题⽬⼤意: 求斐波那契数列中 i : 1~n , j : i+1~n 中 fi*fj 为偶数的个数
思路:两数相乘为偶数则⼀个数为偶数即可斐波那契数列中3的倍数为偶数则只需要求n中为3的倍数的个数计算匹配数减去重复匹配的数量即可
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int main()
{
ll n;cin>>n;
ll k=n/3;
ll ans = k*(n-1) - ((k-1)*k/2);
cout<<ans<<endl;
}
M
题⽬⼤意:给出n个⽂件的路径,你需要删除的,再给出m个⽂件的路径,你不能删除的,如果⼀个⽂件夹中的所有⽂件都可以删除那么就⼀次性删除即可,问最少删除次数
思路:map 存⼀下字符串,先处理⽂件标记⾸先为0,如果不可以删除标记为1,对于已标记为0的字符串,将其标记为2,如果后⾯再次出现那么整个路径都需要删除则ans--
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, n, m;
int main()
{
cin >> t;
while (t--)
{
cin >> n >> m;
int ans = n;
map<string, int> mp;
string s, ss[105];
for (int i = 1; i <= n + m; i++)
{
cin >> ss[i];
s.clear();
for (int j = 0; j < ss[i].size(); j++)
{
if (ss[i][j] == '/')
{
if (i > n) mp[s] = 1; //前n个⽂件需要删除后⾯不能删除
else mp[s] = 0;//所有m路径记为1 其他均为0
}
else s += ss[i][j];
}
}
for (int i = 1; i <= n; i++)
{
s.clear();
for (int j = 0; j < ss[i].size(); j++)
{
if (ss[i][j] == '/')
{
if (mp[s] == 0) mp[s] = 2;//说明可以删去先标记为2 后⾯出现再减
else if (mp[s] == 1) continue;//不能删去
else //标记为2 需要删去
{
ans--;
break;
}
}
else s += ss[i][j];
}
}
cout << ans << endl;
}
}
B
题⽬⼤意:扫雷,⼀个n×m的矩阵,X代表雷,.代表没有雷。
X的权值为0,.的点权值为相邻雷(X)的数⽬,⼀个图的权值为所有权值相加。
现在给你两个图A和图B,求得不超过n m/2次数修改B(.->X 或则X->.)使得sum与A得相同。
(否则输出-1)。
思路:可知A图所有的X变为.,.变为X,图的权值不变,所以如果A跟B中不同元素个数⼤于n m/2,则直接将A图变成相反的即可,且题⽬⼀定有解。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
string a[N], b[N];
int main()
{
int n, m, cnt = 0;
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 0; i < n; i++)
cin >> b[i];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (a[i][j] != b[i][j]) cnt++;
if (cnt > (n * m / 2))
{
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
if (a[i][j] == '.') a[i][j] = 'X';
else a[i][j] = '.';
}
}
for (int i = 0; i < n; i++)
cout << a[i] << endl;
}
D
题⽬⼤意:有⼀个数轴,范围为[ 0 ,n ],数轴上有两个⼈,位置和速度为p1,v1,p2,v2,求出两⼈路程覆盖数轴的最⼩时间。
思路:分类讨论:
三种情况:(假设p1完全在p2的左边,p1<p2)
1. p1,p2相向⽽⾏
2. p1单独⾛全程,或者p2单独⾛全程
3. p1,p2相背⽽⾏,(需要⼆分找到中间相遇点,由分析可知相遇点⼀定在p1,p2之间)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
int t;
double n, p1, p2, v1, v2, ans;
bool check(double mid)
{
double t1 = min(mid - p1 + mid, mid + p1) / v1;
double t2 = min(p2 - mid + n - mid, n - p2 + n - mid) / v2;
ans = min(ans, max(t1, t2));
return t1 < t2;
}
int main()
{
cin >> t;
while (t--)
{
cin >> n >> p1 >> v1 >> p2 >> v2;
if (p1 > p2)
swap(p1, p2), swap(v1, v2);
ans = 1e9 + 10;
//情况1
ans = min(ans, max((n - p1) / v1, p2 / v2));
//情况2
ans = min(ans, min(p1 + n, n - p1 + n) / v1);
ans = min(ans, min(p2 + n, n - p2 + n) / v2);
//情况3
double l = p1, r = p2;
while (r - l > 1e-11)
{
double mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.10f\n", ans);
}
}
I
题⽬⼤意:有n个共圆⼼的圆,半径相差为1,有m条线通过圆⼼将这n个圆平分,求所有交点的距离和。
思路:1.圆⼼点到所有点的距离和(m条直径和),如果m为1,则不⽤考虑。
2.每⼀层的点之间的距离,(两点之间考虑是弧长近,还是⾛两个半径近),加上对称点的距离。
3.每层之间各点距离和。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
const double PI = acos(-1);
double p[N], cir[N];
int main()
{
int n, m;
cin >> n >> m;
double ans = 0, h = PI / m;
if (m > 1)
ans += n * (n + 1) * m;//圆⼼到每个点的距离
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < m; j++)
{
p[i] += min(2.0 * i, j * i * h);//对于⼀个点计算⼀边两点之间的距离
}
p[i] *= 2.0;//添加另⼀边
p[i] += 2.0 * i;//加上对称点
ans += p[i] * m;//算上整个层的距离
ans += (cir[i - 1] + (i - 1) * 2 * m) * 2 * m;//计算本层圆到下层圆的和
cir[i] = cir[i - 1] + (i - 1) * 2 * m + p[i];//前缀和
}
printf("%.10f\n", ans);
}。