Codeforces Round #702 (Div. 3) 全部七题
A. Dense Array
数据范围很小可以直接枚举,对于每个间隔用while循环二倍二倍往里插。
#include <iostream>
using namespace std;
int a[55];
int main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
int n, ans = 0;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 2; i <= n; i++)
{
if(max(a[i], a[i - 1]) * 1.0 / min(a[i], a[i - 1]) > 2.0)
{
int tmp = min(a[i], a[i - 1]) * 2;
ans++;
while(tmp * 2 < max(a[i], a[i - 1]))
{
tmp *= 2;
ans++;
}
}
}
cout << ans << endl;
}
return 0;
}
B. Balanced Remainders
模3可以直接分类讨论,如果余数为0的缺数优先贪心地拿余数为2的数加一来补充(如果余数为2的数多的话),其次拿余数为1的数加2来补充(每个代价为2)。
#include <iostream>
using namespace std;
int n, a[30005], ans;
int main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
ans = 0;
int res[3];
res[0] = res[1] = res[2] = 0;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
res[a[i] % 3]++;
}
res[0] -= n / 3;
res[1] -= n / 3;
res[2] -= n / 3;
if(res[0] < 0)
{
if(res[2] > 0)
{
ans += min(-res[0], res[2]);
if(res[2] >= -res[0])
{
res[2] += res[0];
res[0] = 0;
}
else
{
res[0] += res[2];
res[2] = 0;
}
}
if(res[0] < 0 && res[1] > 0)
{
ans += 2 * min(-res[0], res[1]);
if(res[1] >= -res[0])
{
res[1] += res[0];
res[0] = 0;
}
else
{
res[0] += res[1];
res[1] = 0;
}
}
}
if(res[1] < 0)
{
if(res[0] > 0)
{
ans += min(-res[1], res[0]);
if(res[0] >= -res[1])
{
res[0] += res[1];
res[1] = 0;
}
else
{
res[1] += res[0];
res[0] = 0;
}
}
if(res[1] < 0 && res[2] > 0)
{
ans += 2 * min(-res[1], res[2]);
if(res[2] >= -res[1])
{
res[2] += res[1];
res[1] = 0;
}
else
{
res[1] += res[2];
res[2] = 0;
}
}
}
if(res[2] < 0)
{
if(res[1] > 0)
{
ans += min(-res[2], res[1]);
if(res[1] >= -res[2])
{
res[1] += res[2];
res[2] = 0;
}
else
{
res[2] += res[1];
res[1] = 0;
}
}
if(res[2] < 0 && res[0] > 0)
{
ans += 2 * min(-res[2], res[0]);
if(res[0] >= -res[2])
{
res[0] += res[2];
res[2] = 0;
}
else
{
res[2] += res[0];
res[0] = 0;
}
}
}
cout << ans << endl;
}
return 0;
}
C. Sum of Cubes
直接枚举,注意因为开三次根的精度问题进行判定的时候范围要稍微大一点。正负2可以过。
#include <iostream>
#include <cmath>
using namespace std;
long long x;
int main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> x;
bool flag = 0;
if(x == 1ll)
{
cout << "NO" << endl;
continue;
}
for(long long a = 1; a * a * a < x; a++)
{
long long b0 = pow(x - a * a * a, 1.0 / 3);
long long b1 = b0 - 1, b2 = b0 + 1, b3 = b0 - 2, b4 = b0 + 2, res = x - a * a * a;
if(b0 * b0 * b0 == res || b1 * b1 * b1 == res || b2 * b2 * b2 == res || b3 * b3 * b3 == res || b4 * b4 * b4 == res)
{
//cout << a << ' ' << b0 << ' ' << b1 << ' ' << b2 << ' ' << endl;
flag = 1;
break;
}
}
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
D. Permutation Transformation
按题意直接搜即可。
#include <iostream>
using namespace std;
int n, a[105], dep[105];
void dfs(int l, int r, int d, int mx_pos)
{
int mx_r = 0, mx_l = 0, pos_l, pos_r;
dep[mx_pos] = d;
if(l >= r) return;
for(int i = l; i < mx_pos; i++)
{
if(a[i] > mx_l)
{
mx_l = a[i];
pos_l = i;
}
}
for(int i = mx_pos + 1; i <= r; i++)
{
if(a[i] > mx_r)
{
mx_r = a[i];
pos_r = i;
}
}
if(l <= mx_pos - 1) dfs(l, mx_pos - 1, d + 1, pos_l);
if(r >= mx_pos + 1) dfs(mx_pos + 1, r, d + 1, pos_r);
}
int main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
int mmax = 0, pos;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
if(a[i] > mmax)
{
mmax = a[i];
pos = i;
}
}
dfs(1, n, 0, pos);
for(int i = 1; i <= n; i++) cout << dep[i] << ' ';
cout << endl;
}
return 0;
}
E. Accidental Victory
因为是完全随机的,又说只要有一点可能都算...所以不妨直接讨论最优情况。首先把所有人按照a的大小排序,求出前缀和数组。可以知道当前的人一定可以干掉值比他小的所有人, 相当于当前的人的a值可以到达sum[i]的大小,然后就看靠这个值能否打败下一个人,再创立一个数组ok, ok[i]=1代表i能打败i+1...然后求出ok的后缀和sub,如果sub[i] == n - i + 1,说明i在打败前i-1个人并获取其值后能接连打败剩下的n-i+1个人(最优情况),满足条件,扔进vector里排序,最后输出即可。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define int long long
using namespace std;
struct player
{
int id, a;
} p[200005];
bool cmp(player aa, player bb)
{
return aa.a < bb.a;
}
bool cmp1(player aa, player bb)
{
return aa.id < bb.id;
}
int n;
long long sum[200005];//排序后的前缀和
int sub[200005] = { 0 };
int ok[200005];
signed main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
memset(ok, 0, sizeof(ok));
for(int i = 1; i <= n; i++)
{
cin >> p[i].a;
p[i].id = i;
}
sort(p + 1, p + n + 1, cmp);
sum[0] = 0;
for(int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + p[i].a * 1ll;
if(sum[i] >= p[i + 1].a * 1ll) ok[i] = 1;
}
sub[n] = 1;//第n个一定ok
for(int i = n - 1; i >= 1; i--)
{
sub[i] = sub[i + 1] + ok[i];
}
vector<player> v;
for(int i = 1; i <= n; i++)
{
if(sub[i] == n - i + 1) v.push_back(p[i]);
}
sort(v.begin(), v.end(), cmp1);
cout << v.size() << endl;
for(int i = 0; i < v.size(); i++) cout << v[i].id << ' ';
cout << endl;
}
return 0;
}
F. Equalize the Array
首先先排序。注意到这个题和每个ai的值并没有关系,因此排序后扫一遍数组统计出每个值对应有多少个数。然后把这些数放进vector再排序,从小到大遍历,执行一个类似阶梯里求最大矩形的过程(只不过用不到单调栈),用mmax = max(mmax, v[i] * ((int)v.size() - i));更新最大的矩形面积,再用总的和减去面积就是要删除的元素个数。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n, a[200005];
int main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1);
int cnt = 0;
vector<int> v;
a[n + 1] = 0x3f3f3f3f;
for(int i = 1; i <= n + 1; i++)
{
if(i == 1)
{
cnt++;
continue;
}
if(a[i] == a[i - 1])
{
cnt++;
}
else
{
v.push_back(cnt);
cnt = 1;
}
}
sort(v.begin(), v.end());//类似单调栈,最大矩形
int mmax = 0, tot = 0;
for(int i = 0; i < v.size(); i++)
{
//cout << v[i] << ' ';
tot += v[i];
mmax = max(mmax, v[i] * ((int)v.size() - i));
}
//cout << endl;
cout << tot - mmax << endl;
}
return 0;
}
G. Old Floppy Drive
不妨设sum数组为前缀和数组,mx[i]代表前缀和数组里1~i最大的一个前缀和(因为可能有负数,前缀和数组不一定是单调不减,但mx数组一定是单调不减的,所以利用mx数组来进行二分查找)。
如果mx[n] >= x,说明只遍历一遍前缀和数组一定能找到一个位置满足条件,直接在mx用lower_bound二分查找x即可。
如果mx[n] < x:意味着只遍历一轮不够。
首先,如果sum[n] <= 0,说明肯定是越更新越小(联想spfa判负环),永远也不可能停止,直接输出-1.
如果sum[n] > 0,设d = x - mx[n],则至少要循环ceil(d / sum[n])圈。但是向上取整之后在最后一圈就不一定是到mx[n]了,有可能在下标更小的位置就结束循环,这个位置可以根据lower_bound函数查找x - ceil(d * 1.0 / sum[n]) * sum[n],再加上 ceil(d * 1.0 / sum[n]) * n(每轮移动n次)即可。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
using namespace std;
int n, m, a[200005];
long long sum[200005], mx[200005];
signed main()
{
freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n >> m;
sum[0] = 0;
mx[0] = -0x3f3f3f3f;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
mx[i] = max(mx[i - 1], sum[i]);
}
for(int i = 1; i <= m; i++)
{
long long x;
cin >> x;
if(mx[n] >= x)
{
cout << lower_bound(mx + 1, mx + n + 1, x) - 1 - mx << ' ';
}
else
{
if(sum[n] <= 0)
{
cout << -1 << ' ';
continue;
}
long long d = x - mx[n];
cout << lower_bound(mx + 1, mx + n + 1, x - sum[n] * (long long)ceil(d * 1.0 / sum[n])) -mx - 1 + (long long)ceil(d * 1.0 / sum[n]) * n << ' ';
//注意ceil返回的是double 要强制转换一下
}
}
cout << endl;
}
return 0;
}