Codeforces Round 919 (Div. 2)
Codeforces Round 919 (Div. 2)
A. Satisfying Constraints
解题思路:
确定最大下界和最小上界。
然后看有多少个不可选数在界内。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
void solve()
{
int n;
cin >> n;
ll l = 0;
ll r = 1e18;
vector<ll> v;
for (int i = 1; i <= n; i++)
{
int t = 1;
ll x;
cin >> t >> x;
if (t == 1)
{
l = max(l, x);
}
else if (t == 2)
{
r = min(r, x);
}
else
{
v.push_back(x);
}
}
sort(v.begin(), v.end());
int cnt = 0;
for (auto x : v)
{
if (x >= l && x <= r)
{
cnt++;
}
}
cout << max(0ll, r - l + 1 - cnt) << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B. Summation Game
解题思路:
枚举爱丽丝删最后\(0个,1个,...k个\)。
鲍勃总是将最大的\(x\)个变负。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
void solve()
{
int n;
cin >> n;
int k, x;
cin >> k >> x;
vector<ll> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
sort(a.begin() + 1, a.end());
for (int i = 1; i <= n; i++)
{
a[i] += a[i - 1];
}
ll ans = -1e18;
for (int i = n; i >= n - k; i--)
{
ll l = max(1, i - x + 1);
ans = max(ans, a[n] - (a[n] - a[i]) - 2 * (a[i] - a[l - 1]));
}
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C. Partitioning the Array
解题思路:
预处理出所有因子。
遍历因子。
对于每个因子\(p\),搜前\(p\)个,然后每个跳\(p\)搜。(就是搜每个子数组第一个,然后搜每个子数组第二个。。。)这样的顺序搜索数组每个元素。
若所有子数组对应位置之差的最大公因数不为\(1\),则分数加一。
举例:
\([1,2],[3,4],[5,6]\)。
上述情况的差数有\(3 - 1= 2,5 - 3 = 2,4 - 2 = 2,6 - 4= 4.(2,2,2,2)\).
\(求(2,2,2,2)最大公因数即可\)。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
void solve()
{
int n;
cin >> n;
vector<int> fac;
for (int i = 1; i <= n / i; i++)
{
if (n % i == 0)
{
fac.push_back(i);
if (n / i != i)
{
fac.push_back(n / i);
}
}
}
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
// for (auto p : fac)
// {
// cout << p << ' ';
// }
ll ans = 0;
for (auto p : fac)
{
bool f = true;
ll g = 0;
for (int i = 1; i <= p; i++)
{
for (int j = i + p; j <= n; j += p)
{
g = gcd(g, abs(a[j] - a[j - p]));
if (g == 1)
{
// cout << p << ' ' << j << endl;
f = false;
break;
}
}
if (!f)
{
break;
}
}
if (f)
{
// cout << g << endl;
ans++;
}
}
printf("%lld\n", ans);
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
D. Array Repetition
解题思路:
只有单独插入的数需要记录位置。
翻倍添加的数模上翻倍时原序列的长度,一定会对应上原序列的某个数的位置。
如果原位置是插入的数,直接取出记录的数。
否则,继续往前模。每次模完长度至少减半,所以时间复杂度可过。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
ll n, q;
cin >> n >> q;
vector<pii> v;
map<ll, ll> mp;
i128 len = 0;
for (int i = 1; i <= n; i++)
{
int t, x;
scanf("%d %d", &t, &x);
if (t == 1)
{
len = len + 1;
mp[(ll)len] = x;
}
else
{
if (len > 1e18)
{
continue;
}
ll t = 0;
if (len <= 1e18)
{
t = len;
len = len * (x + 1);
}
if (len > 1e18)
{
len = 1e18 + 1;
}
v.push_back({len, t});
}
}
sort(v.begin(), v.end());
// for (auto x : v)
// {
// cout << x.fi << ' ' << x.se << endl;
// }
while (q--)
{
ll x = 0;
scanf("%lld ", &x);
while (!mp.count(x))
{
auto it = lower_bound(v.begin(), v.end(), (pii){x, 0ll});
ll len = (*it).se;
x %= len;
if (x == 0)
{
x = len;
}
}
printf("%lld ", mp[x]);
}
cout << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号