这次div3打的很烂,明明很简单的东西想的很复杂,甚至读了假题,以后做题既不能想复杂了,也不要想的太简单。
A. Game with Integers
有两个人在玩一个游戏,最开始有一个整数 n 。轮到自己时,玩家可以在当前整数上加上 1 或减去 1 。玩家轮流操作;第一个先下。如果第一个玩家操作后整数能被 3 整除,那么他获胜。如果 10 步已过而第一个玩家没有获胜,则第二个玩家获胜。
分析:
如果这个数一开始就是3的倍数那么第二个玩家总是能根据第一个玩家的操作把这个数变回最开始的数,而题目要求的是第一个玩家操作后是3的倍数才能获胜,而他这时不得不操作,这个局面会一直持续下去,所以第二个玩家获胜,如果这个数一开始不是3的倍数,如果n%3==1,那么第一个玩家减1即可获胜,如果n%3==2,第一个玩家加1即可获胜
code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
void solve() {
int n; cin >> n;
cout << (n % 3 ? "First" : "Second") << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
B. 250 Thousand Tons of TNT
分析:
典型的不要把问题想复杂,而且读懂题意很重要,这个题说了一大段,其实就是给你n个物品,让你把它们在不改变顺序的前提下分为等量的k堆,使得最大的一堆和最小的一堆差值最大,直接暴力枚举n的约数即可,需要带个前缀和优化不然会tle。
code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
void solve() {
int n; cin >> n;
vector<int> a(n + 1);
cin >> a;
int ans = 0;
vector<int> pre(n + 1);
for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i];
for (int i = 1; i <= sqrt(n); i++) {
if (n % i == 0) {
int mx = -1e18, mn = 1e18;
for (int j = i; j <= n; j += i) {
mx = max(mx, pre[j] - pre[j - i]);
mn= min(mn, pre[j] - pre[j - i]);
}
ans = max(ans, mx - mn);
mx = -1e18, mn = 1e18;
for (int j = n/i; j <= n; j += n/i) {
mx = max(mx, pre[j] - pre[j - n/i]);
mn = min(mn, pre[j] - pre[j - n/i]);
}
ans = max(ans, mx - mn);
}
}
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
C. Yarik and Array
分析:
给定一个数组,长度为n,统计奇偶交替的子数组的最大和,一眼dp,但是这里我写的比较复杂,其实一维就够了,当时不知道为啥写了个三维的,dp[i][j][k]表示前i个数,是否以第i个数结尾(1表示是,0表示否),且前一个数是奇数/偶数(直接a[i]&1表示奇偶性),状态转移见代码。
code1
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int dp[(int)2e5 + 5][2][2];
void solve() {
int n; cin >> n;
vector<int> a(n + 1);
cin >> a;
int ans = 0;
for (int i = 1; i <= n; i++) dp[i][0][0]= dp[i][0][1] = dp[i][1][0] = dp[i][1][1] = 0;
dp[1][1][a[1]&1] = a[1];
for (int i = 2; i <= n; i++) {
dp[i][0][0] = dp[i - 1][0][0];
dp[i][0][1] = dp[i - 1][0][1];
dp[i][1][(a[i] & 1)] = max(dp[i - 1][1][(a[i] & 1) ^ 1], dp[i - 1][0][(a[i] & 1) ^ 1]) + a[i];
}
for (int i = 1; i <= n; i++) {
ans = max(ans, dp[i][1][a[i] & 1]);
}
if (!ans) ans = *max_element(all(a));
cout << ans << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
code2
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}void solve() {
int n; cin >> n;
vector<int> a(n + 1), f(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i], f[i] = 0;
}
f[1] = a[1];
for (int i = 2; i <= n; i++)
{
if ((a[i] & 1) * (a[i - 1] & 1) == 0 && (a[i] & 1) + (a[i - 1] & 1) == 1) f[i] = max(f[i - 1] + a[i], a[i]);
else f[i] = a[i];
}
int mx = -1e18;
for (int i = 1; i <= n; i++) mx = max(mx, f[i]);
cout << mx << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
D. Yarik and Musical Notes
分析:
很沙必的一个题,把题目看错了导致做了很久的假题,题意实际上是给你一个数组b,求
(i,j)的对数,使得=的对数,(i>j),重点来了,b数组代表的是2的幂次方,比如b1=2,b1实际上指的是2的2次方也就是4,把其中一个数当成已知数去求解另外一个值,手摸一下就能发现一边是幂函数,一边是指数函数,交点只有一个就是1和2,否则就是它本身,实在不行可以打个表也能发现规律,我们那map存一下各个数有多少个,然后对数组去重,那么每个数的对数就应该是(m-1)*m/2,如果是1则额外统计一下即可。
code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int n;
int a[N];
int tr[N];
int lowbit(int n) {
return n & (-n);
}
void add(int pos, int c) {
for (int i = pos; i <= n; i += lowbit(i)) tr[i] += c;
}
int sum(int pos) {
int res = 0;
for (int i = pos; i; i -= lowbit(i)) res += tr[i];
return res;
}
void solve() {
int n; cin >> n;
vector<int> a(n + 1);
map<int, int> st;
for (int i = 1; i <= n; i++) {
cin >> a[i];
st[a[i]]++;
}
sort(all(a));
a.erase(unique(all(a)), a.end());
int res = 0;
for (int i : a) {
if (i == 1) res += st[1] * st[2];
res += st[i] * (st[i] - 1) / 2;
}
cout << res << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
E. Queue Sort
分析:
给定一个数组,
可以多次执行下面的操作:
- 提取数组的第一个元素,并将其插入末尾;
- 将这个元素与前一个元素对调,直到它成为第一个元素或严格大于前一个元素。
要求你确定对数组进行排序所需的最少操作数,或者输出-1表示不可能排好序。
观察发现对于数组最小的元素,如果其已经位于数组的首位,则操作再也没有意义,因为没有一个元素严格小于它,所以当数组这个时候仍然没有排好序,那么它就不可能被排好序,反之排好序所需的最小次数就是把最小的数移到第一个数所需的最小次数。
code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}void solve() {
int n; cin >> n;
vector<int> a(n+1);
cin >> a;
int pos = min_element(all(a)) - a.begin();
for (int i = pos; i < n; i++) {
if (a[i] > a[i + 1]) return void(cout << -1 << endl);
}
cout << pos - 1 << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}
F. Alex's whims
分析:
给你一个数n,让我们构建一棵树,然后给出q个询问,每次可以执行以下操作
- 选择顶点 u 、 v1 和 v2 ,使得 u 和 v1之间有一条边, u和 v2之间没有边。然后删除 u 和 v1 之间的边,并在 u和 v2之间添加一条边。如果操作后图形不再是树形,则不能执行此操作。
树叶是树中的一个顶点,它正好有一条边与之相连。
树中两个顶点 u和 v 之间的距离是从顶点 u到顶点 v 必须经过的最小边数。
每次执行一次(或0次)操作使得树中存在两个叶节点的距离等于di。
我们可以把树退化成链表,然后把第一个节点拿来凑数,比如n=5,q=2,d1=2,d2=3
移动一个点即可。
code
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#define int long long
typedef long long ll;
#define PII pair<int,int>
#define endl '\n'
#define x first
#define y second
#define all(n) (n).begin() + 1,(n).end()
const int N = 6e5 + 5;
const int mod = 1e9 + 7;
void prvec(vector<int> a) {
for (auto i : a) cout << i << '|';
cout << endl;
}
ostream& operator<<(ostream& ou, vector<int> a) {
for (int i = 0; i < a.size(); i++) ou << a[i] << ' ';
return ou;
}
istream& operator>>(istream& in, vector<int>& a) {
for (int i = 1; i < a.size(); i++) in >> a[i];
return in;
}
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}void solve() {
int n, q;
cin >> n >> q;
vector<int> d(q + 1);
for (int i = 1; i <= q; i++) {
cin >> d[i];
}
for (int i = 1; i < n; i++) {
cout << i << " " << i + 1 << endl;
}
int pre = 2;
d[0] = n - 1;
for (int i = 1; i <= q; i++) {
if (d[i] == d[i - 1]) {
cout << "-1 -1 -1" << endl;
}
else {
cout << 1 << " " << pre << " " << n - d[i] + 1 << endl;
pre = n - d[i] + 1;
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;cin >> _;
while (_--) solve();
}