链接:Codeforces Round 998 (Div. 3)
A:Fibonacciness
大意:
a1 - a5,给定1 2 4 5,求最大满足a[i + 2] = a[i + 1] + a[i]的i的数
思路:
a3也不管情况重复没重复,三种情况满足情况取最后结果最大值即可
后来发现随便填两种就行,不过要的是速度,细想浪费时间
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 998244353;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
vi a(10);
cin >> a[1] >> a[2] >> a[4] >> a[5];
a[3] = a[1] + a[2];
int ans = 0, tmp = 0;
for (int i = 3; i <= 5; i++)
if (a[i - 2] + a[i - 1] == a[i])tmp++;
ans = max(ans, tmp);
tmp = 0;
a[3] = a[4] - a[2];
for (int i = 3; i <= 5; i++)
if (a[i - 2] + a[i - 1] == a[i])tmp++;
ans = max(ans, tmp);
tmp = 0;
a[3] = a[5] - a[4];
for (int i = 3; i <= 5; i++)
if (a[i - 2] + a[i - 1] == a[i])tmp++;
ans = max(ans, tmp);
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
B:Farmer John's Card Game
大意:
卡牌游戏,给定n头牛,每头牛m张牌,牛顺序出牌m轮,求是否存在一个顺序,使得每次出的牌都比上次的牌大。如果不能出完,输出-1,否则输出顺序。
思路:
给每头牛的牌从小到大排序,然后以第一张牌大小为顺序,如果有牛第一张牌大于等于n,就直接-1。
然后记录一个上次的牌大小,依次遍历即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 998244353;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n, m;
cin >> n >> m;
vvi a(n + 1, vi(m));
for (int i = 1; i <= n; i++)
for (int j = 0; j < m; j++)
cin >> a[i][j];
for (int i = 1; i <= n; i++)
sort(a[i].begin(), a[i].end());
vi p(n + 1);
for (int i = 1; i <= n; i++)
if (a[i][0] < n)
p[a[i][0] + 1] = i;
else
{
cout << -1 << endl;
return;
}
int last = -1;
for(int i = 0; i < m; i ++)
for (int j = 1; j <= n; j++)
{
if (a[p[j]][i] < last)
{
cout << -1 << endl;
return;
}
else last = a[p[j]][i];
}
for (int i = 1; i <= n; i++)cout << p[i] << ' ';
cout << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
C:Game of Mathletes
大意:
A和B玩游戏,黑板上n(n为偶数)个数,A擦掉一个,B擦掉一个,进行n/2轮,每轮若两人擦掉的数的和为k,分数+1,否则分数不变,A想分最小,B想分最大。求最大分。
思路:
因为偶数个数,所以就算按照最佳策略,Alice也没法改变结果。最后最多能凑出几个答案就是几个。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 998244353;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n, k;cin >> n >> k;
vi a(n);
for (int i = 0; i < n; i++)cin >> a[i];
unordered_map<int, int> mp;
for (int i = 0; i < n; i++)mp[a[i]]++;
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
int ans = 0;
for (auto i : a)
{
if (i < k / 2 && mp.count(k - i))ans += min(mp[i], mp[k - i]);
else if (i == k / 2)
{
if (k % 2 == 0)ans += mp[i] / 2;
else if (mp.count(k - i))ans += min(mp[i], mp[k - i]);
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
D:Subtract Min Sort
大意:
一个数组,可以进行任意次操作,每次操作相邻两个数减去这两个数的较小值,问问是否可以使得数组非递减。
思路:
每次操作,两个数就至少有一个变成0,那么如果后面的不是非递减,前面的就需要全为0
而且观察到,(我蒙的,反证蒙的)从前往后依次进行操作,则最后得到的序列如果非递减就非递减,不是就不行。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 998244353;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
vi a(n);
for (int i = 0; i < n; i++)cin >> a[i];
for (int i = 1; i < n; i++)
{
int num = min(a[i], a[i - 1]);
a[i] -= num;
a[i - 1] -= num;
}
for(int i = 1; i < n; i ++)
if (a[i] < a[i - 1])
{
cout << "NO" << endl;
return;
}
cout << "YES" << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
E:Graph Composition
大意:
给两个图,对第一个图可以进行加边或者减边操作,求最少操作数,使得两个图的任意两点连通性相同。
思路:
任意两点连通性相同,首先图2的连通性是已知的,我们需要对图1加边减边,
首先考虑减边,因为加边再减边好像不太好做。看图1中哪些边是必须要去掉的,遍历图1的边,如果两点在图2中是连着的,那么这个边就可以留下,如果没连着,这个边就一定不能要。
操作完后就得到了新的图1,图1有的边图2一定有,图2没的边图1一定没有。
然后就考虑加边,我们需要找到图2连通集合,把图2有图1没有的边加上去。
这样图2有的图1一定有,图2没的图1一定没有.
使用并查集实现即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 998244353;
#define pb push_back
#define vi vector<int>
#define vvi vector<vector<int>>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
int find(vi &p, int x)
{
if (p[x] != x)p[x] = find(p, p[x]);
return p[x];
}
void solve()
{
int n, m, k;
cin >> n >> m >> k;
vii s1(m), s2(k); // 边
vi p1(n + 1), p2(n + 1);
for (int i = 1; i <= n; i++)
p1[i] = p2[i] = i;
for (int i = 0; i < m; i++)
cin >> s1[i].ff >> s1[i].ss;
for (int i = 0; i < k; i++)
cin >> s2[i].ff >> s2[i].ss;
for (int i = 0; i < k; i++) // 图2集合确定
p2[find(p2, s2[i].ff)] = find(p2, s2[i].ss);
int ans = 0;
// 删边操作,这里在加边时进行,删除的不加即可
for (auto& [x, y] : s1)
{
if (find(p2, x) != find(p2, y))ans++;
else p1[find(p1, x)] = find(p1, y);
}
//同一集合下元素
unordered_map<int, vi> mp;
for (int i = 1; i <= n; i++)mp[find(p2, i)].push_back(i);//根节点下的元素
for(int i = 1; i <= n; i ++)
for (auto& x : mp[i])
if (find(p1, x) != find(p1, i)) //不在就加边
{
ans++;
p1[find(p1, x)] = find(p1, i);
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/