赞
踩
目录
思路:直接遍历一遍,记录有多少个人的得分大于等于L。
代码:
- void solve()
- {
- cin >> n >> m;
- int sum = 0;
- for(int i = 1; i <= n; i ++)
- {
- int t;
- cin >> t;
- if(t >= m) sum ++;
- }
- cout << sum << endl;
- }
思路:如果输入的数是比l小的答案为l,如果输入的数在l到r的范围内,则答案为数本身,如果输入的数大于r的答案为r。
代码:
- void solve()
- {
- int l, r;
- cin >> n >> l >> r;
- for(int i = 1; i <= n; i ++)
- {
- int t;
- cin >> t;
- if(t <= l)
- {
- cout << l << ' ';
- }
- else if(l < t && t < r)
- {
- cout << t << ' ';
- }
- else cout << r << ' ';
- }
- }

思路:直接暴力枚举x和y就好。枚举到x的平方大于n的时候break。枚举的时候注意y的取值,可以是sqrt(abs(n - x * x)) + 1, 或者是 sqrt(abs(n - x * x))。int sqrt()的时候 :因为返回类型是整数,结果只保留整数部分,小数部分将被舍去。
代码:
- void solve()
- {
- int l, r;
- cin >> n;
- int sum = n;
- for(int i = 1; i * i <= 2e12; i ++)
- {
- int t = i * i;
- if(t > n) break;
- int p = abs(n - t);
- int q = sqrt(p);
- int su = abs(t + q * q - n);
- q ++;
- sum = min(sum, su);
- su = abs(t + q * q - n);
- sum = min(sum, su);
- }
- cout << sum << endl;
- }

思路:题目要求
我们设三个点的坐标是(x1, y1), (x2, y2), (x3, y3) 其中 x2 = x1 ,y2 = y3。所以我们只需要找出第二个点 (x2, y2),对答案的贡献就是(row[i] - 1) * (col[j] - 1) 其中row[i] 表示 第i行有多少个元素是o,col[j] 表示第j行有多少个元素是o。
代码:
- int n, m, k;
- int row[2020], col[2020];
- char c[2020][2020];
- void solve()
- {
- cin >> n;
- for(int i = 1; i <= n; i ++)
- {
- for(int j = 1; j <= n; j ++)
- {
- cin >> c[i][j];
- if(c[i][j] == 'o') row[i] ++, col[j] ++;
- }
- }
- int sum = 0;
- for(int i = 1; i <= n; i ++)
- {
- for(int j = 1; j <= n; j ++)
- {
- if(c[i][j] == 'o')
- {
- sum += ((row[i] - 1) * (col[j] - 1));
- }
- }
- }
- cout << sum << endl;
- }

思路:运用set和map,map存每个数出现的次数,set存每个数是否出现过,当一个数的出现次数变成0后,set将其加入,反之当一个数出现次数大于0的时候,set将其删除。首先,我们先把0到n都存到set里面去(初始时0 - n在数组中都没出现过).。 然后按照题目要求模拟即可,每次操作后的答案就是set中存的第一个元素。set中存的元素是排好序的。
代码:
- void solve()
- {
- cin >> n;
- cin >> m;
- map<int, int> mp;
- set<int> s;
- for(int i = 0; i <= n; i ++)
- {
- s.insert(i);
- }
- for(int i = 1; i <= n; i ++)
- {
- cin >> a[i];
- mp[a[i]] ++;
- s.erase(a[i]);
- }
- for(int i = 1; i <= m; i ++)
- {
- int op, l, r;
- cin >> l >> r;
- mp[a[l]] --;
- if(mp[a[l]] == 0) s.insert(a[l]);
- a[l] = r;
- mp[a[l]] ++;
- s.erase(r);
- cout << *s.begin() << endl;
- }
-
- }

思路:二分答案,利用前缀和优化。
x和y这两个元素可以分开看,相当于一维里面的两个直线。
如果正方形边长越大,我们需要的移动次数越少,相反,正方形边长越小,需要移动的次数越多。这里有一个单调性,因此我们可以二分最终的正方形边长。边长固定了,考虑到最优情况下,覆盖的线段必定有一端点上的点是从来没移动过的,因此我们可以枚举这个作为边界的点。然后计算需要移动的次数。
我们先将坐标从小到大排序,然后预处理出一个前缀坐标和。注意需要分别枚举作为左端点的点和作为右端点的点。
两个维度分别取所需移动次数的最小值,其和不超过k则边长可行。
(代码中我把k的变量名定义为m了。抱一丝qwq)
代码:
- int x[N], y[N], sumx[N], sumy[N];
- int fun(int a[], int s[], int mid)
- {
- int ans = 1e18;
- for(int i = 1; i <= n; i ++)
- {
- int t = i * a[i] - s[i];
- int R = a[i] + mid;
- int l = 1, r = n;
- while(l < r)
- {
- int midd = l + r >> 1;
- if(a[midd] > R) r = midd;
- else l = midd + 1;
- }
- if(a[l] > R)
- {
- t += s[n] - s[l - 1] - (n - l + 1) * R;
- }
- ans = min(ans, t);
- }
- for(int i = n; i >= 1; i --)
- {
- int t = s[n] - s[i - 1] - (n - i + 1) * a[i];
- int L = a[i] - mid;
- int l = 1, r = n;
- while(l < r)
- {
- int midd = l + r + 1 >> 1;
- if(a[midd] < L) l = midd;
- else r = midd - 1;
- }
- if(a[l] < L)
- {
- t += l * L - s[l];
- }
- ans = min(ans, t);
- }
- return ans;
- }
- bool check(int mid)
- {
- int t = fun(x, sumx, mid) + fun(y, sumy, mid);
- return t <= m;
- }
- void solve()
- {
- cin >> n >> m;
- for(int i = 1; i <= n; i ++)
- {
- cin >> x[i] >> y[i];
- }
- sort(x + 1, x + 1 + n);
- sort(y + 1, y + 1 + n);
- for(int i = 1; i <= n; i ++)
- {
- sumx[i] = x[i] + sumx[i - 1];
- sumy[i] = y[i] + sumy[i - 1];
- }
- int l = 0, r = 1e9;
- while(l < r)
- {
- int mid = l + r >> 1;
- if(check(mid)) r = mid;
- else l = mid + 1;
- }
- cout << l << endl;
- }

链接:TOYOTA SYSTEMS Programming Contest 2023(AtCoder Beginner Contest 330) - AtCoder
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。