1,040
社区成员
发帖
与我相关
我的任务
分享这是我参加朝闻道知识分享大赛的第二十一篇文章。
下面是对 codeforces Educational Codeforces Round 159 的前三道题的讲解,坑点挺多的,不过却都可以作为经验教训。
题意:
给定仅包含 01 的字符串,每次可以往字符串某个位置插入 0 或者 1,如果相邻两个字符相同,则插入1,否则插入0,问是否可以在任意次操作下,使得字符串中,0 的个数严格大于 1 的个数。
思路:
显然,如果字符串中包含有相邻的 01,那么一定可以创造出无限个0,因此剩余的就是全 0 或者全 1 的情况了,直接分类讨论即可,代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
int main()
{
IOS;
cf (_)
{
int n;
cin >> n;
string s;
cin >> s;
bool ok = false;
for (int i = 0; i + 1 < n; i++)
{
if (s[i + 1] != s[i])
{
ok = true;
break;
}
}
if (ok) cout << "YES\n";
else if (s[0] == '1') cout << "NO\n";
else cout << "YES\n";
}
return 0;
}
题意:大学生在大学期间需要修够一定的学分才可以毕业,已知获取学分有 2 个途径,分别是听课和完成习题。已知习题是每周可以做一道,做完可以获得固定的学分,而课程是每天可以上一节,上完也是获取固定的学分。但一天最多只能同时上一次课和完成不超过2个的习题,问在修满学分的情况下,最多可以休息多少天?
思路:
显然,如果学习一天的话一定是尽可能多学点,如果能学1节课与2个练习,则优先考虑,进而考虑1节课和仅剩1个练习,最后是每天1个练习,按照这种思路模拟即可。
解法一:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
void solve()
{
ll n, p, l, t;
cin >> n >> p >> l >> t;
ll cnt = n / 7 + (n % 7 != 0); // cnt个任务
// 先3天,后全是1天
if (cnt % 2 == 0)
{
ll days = cnt / 2;
ll every = t * 2 + l;
if (days * every >= p)
{
ll l = 1, r = days;
while (l < r)
{
ll mid = l + r >> 1;
if (mid * every >= p) r = mid;
else l = mid + 1;
}
cout << (n - l) << "\n";
}
else
{
p -= days * every;
ll last = p / l + (p % l != 0);
cout << n - (days + last) << "\n";
}
}
else
{
ll days = cnt / 2;
ll every = t * 2 + l;
//是不是前3种的天
if (days * every >= p)
{
ll l = 1, r = days;
while (l < r)
{
ll mid = l + r >> 1;
if (mid * every >= p) r = mid;
else l = mid + 1;
}
cout << (n - l) << "\n";
}
else
{
p -= days * every;
if (p <= l + t) cout << n - (days + 1) << "\n";
else
{
p -= l + t;
ll last = p / l + (p % l != 0);
cout << n - (days + 1 + last) << "\n";
}
}
}
}
int main()
{
IOS;
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
解法二:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
void solve()
{
ll n, p, l, t;
cin >> n >> p >> l >> t;
ll cnt = n / 7 + (n % 7 != 0);
ll days = cnt / 2 + (cnt % 2 != 0);
ll mx = days * l + cnt * t;
if (mx >= p) // mx够
{
ll last_day_sum = l + (cnt % 2 != 0 ? t : 2 * t);
if (mx - last_day_sum < p) cout << n - days << "\n";
else
{
ll l2 = 1, r2 = days - 1;
ll every = 2 * t + l;
while (l2 < r2)
{
ll mid = l2 + r2 >> 1;
if ((__int128_t)mid * every >= p) r2 = mid;
else l2 = mid + 1;
}
cout << n - l2 << "\n";
}
}
else
{
ll last = p - mx;
ll last_day = last / l + (last % l != 0);
cout << n - (days + last_day) << "\n";
}
}
int main()
{
IOS;
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
题意: 给定 n 个数,每个数互不相同,你需要加入一个与其余 n 个数不同的新数,然后选择一个固定的数 x,每次往 n + 1 个数的数组中,选取一个数令其 + x,最终需要让所有数相同,问最少操作次数?
思路:
显然,有最大公约数的概念。即选择的 x 是这 n 个数的最大公约数,那么其次第 n + 1 个数怎么选择呢,通过模拟找规律或证明可知,选择的数一定是小于原 n 个数组中最大的那个数,找到第一个小于最大数的且满足相差是最大公约数(d)的倍数,因此最后计算答案贡献即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
#define cf(_) int _;cin >> _;while(_--)
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
int main()
{
IOS;
cf (_)
{
int n;
cin >> n;
vector<ll> a(n + 2);
map<ll, ll> mp;
for (int i = 1; i <= n; i++) cin >> a[i], mp[a[i]]++;
if (n == 1)
{
cout << 1 << "\n";
continue;
}
sort(a.begin() + 1, a.end() - 1);
ll d = 0;
for (int i = 1; i + 1 <= n; i++)
{
ll t = a[i + 1] - a[i];
d = gcd(d, t);
}
// cout << d << "\n";
ll res = 0;
for (ll i = a[n]; i >= -1e18; i -= d)
{
if (!mp.count(i))
{
res = i;
break;
}
}
assert(d != 0);
ll ans = 0;
a[n + 1] = res;
for (int i = 1; i <= n + 1; i++)
{
ans += abs(a[i] - a[n]) / d;
}
cout << ans << "\n";
}
return 0;
}