A题
☠速度保持(2min出)
题意
长度为n的排列是一个数组,其中包含n个从1到n的任意整数的任意整数。
F(p)= sort([p1 + p2,p2 + p3,…,pn-1 + pn])。
例如,如果n = 4且p = [1,4,2,3],
则指纹由F(p)= sort([1 + 4,4 + 2,2 + 3])= sort([5,6,5])= [5,5,6]。
您将得到长度为n的排列p。
您的任务是找到具有相同指纹的其他排列p’。
如果存在一些索引i使得pi≠p’i,则认为两个置换p和p’是不同的。
题解
倒着输出就好了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e4 + 10;
const int INF = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
int a[102];
for(int i = 0; i < n; i++)scanf("%d", &a[i]);
for(int i = n - 1; i >= 0 ; i--) printf("%d ", a[i]);
printf("\n");
}
}
B题
☠思路理清楚再写,别越弄越糊涂了!
题意
一个由n个整数组成的数组a,保证
∑
i
=
0
n
−
1
=
0
;
\sum_{i = 0}^{n-1} = 0;
∑i=0n−1=0;
在一个操作中,您可以选择两个不同的索引i和j(1≤i,j≤n),将ai减1,然后将aj加1。
如果i <j,则此操作是免费的,否则将花费一枚硬币。
为了使所有元素等于0,您必须花费多少枚硬币?
题解
把每个正整数与后面的负数相加,直到和为负数,或者遍历完成,结束,存入另一个数组里。
保证最后这个数组的形式为 :负数 负数 … 负数 正数 … 正数 正数
把所有的正数相加,即为答案。
(因为,这种情况下,任意两个数,ai < aj, ai再减一 aj 再加一会浪费。
接下去,为由不用硬币 到 用 硬币 的转折状态)
我的代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const int INF = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
ll a[MAX] = {0ll};
ll b[MAX] = {0ll};
for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
int cnt = 0;
for(int i = 0; i < n;) {
if(a[i] <= 0) b[cnt++] = a[i++];
else {//由正数开始
ll tmp = a[i];
i++;
while(1) {
//相加为负数,则终止
if(tmp < 0) break;
tmp += a[i++];
if(i >= n) break;
}
b[cnt++] = tmp;
}
}
int pos = 0;
for(int i = 0; i < cnt; i++) {
if(b[i] < 0) pos = i;
}
ll ans = 0;
for(int i = pos + 1; i < cnt; i++) {
ans += b[i];
}
printf("%lld\n", ans);
}
}
C题
☠别慌,别乱
题意
给出n个字符 由0 和1 以及?(?可以变成0 或 1)组成的数组
问能不能做到每k个,就有相同数量的1,以及1的数量等于k / 2
题解
以k为循环,k + i,2 * k + i, 3 * k + i . . .中有明确两个不一样,那么一定是NO
如果,只出现一种数字, 这个数字的个数++,要求两个个数不能大于k / 2.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const int INF = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, k;
scanf("%d%d", &n, &k);
string a;
cin >> a;
int cnt0 = 0, cnt1 = 0;
bool flag = 1;
for(int i = 0; i < k; i++) {
int tmp = -1; //!
for(int j = i; j < n; j += k) {
if(a[j] == '?') continue;
if(tmp != -1 && tmp != a[j] - '0') {//虽是?,但是明确有两个不一样
flag = 0;
break;
}
tmp = a[j] - '0';
}
if(tmp != -1) {
if(tmp == 0) cnt0++;
else cnt1++;
}
}
if(flag && cnt1 <= k / 2 && cnt0 <= k / 2) printf("YES\n");
else printf("NO\n");
}
}
D题
☠树上博弈,其实我是被内心恐惧 树 的!
题意
在一棵树上,Alice 和 Bob在两个点上,可以移动的距离为da 和 db
如果 Alice 可以与 Bob 到一个点上,则Alice 赢,反之Bob赢。
题解
情 况 一 情况一 情况一
如果Alice和Bob之间的距离小于等于da,那么Alice就赢了。
思考:
临界条件为:
Alice 和 Bob 可以在树最长的链上–树的直径上运动
情 况 二 情况二 情况二
当Alice和Bob之间的距离为da+1,也就是若Alice再靠近Bob一步且Bob不操作,Bob就输了。这个时候,Bob就需要跳到离Alice新位置的距离大于da的位置。Alice用最优操作的情况下,Bob的移动距离要大于2 * da +1。
(db >= 2 * da + 1)
且要使操作允许,树的直径 要 >= 2 * da +1
结
论
:
结论:
结论:
当且仅当Alice和Bob的初始距离大于da,且db和树的直径都大于等于2 * da +1时,Bob胜,反之Alice胜。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 2e5 + 10;
int n, a, b, da, db;
int diam;
int dist;
int deep[MAX];
vector <int> G[MAX];
int root1, root2;
void dfs(int u, int fa, int &diam, int &root) {//diam,root要变的
deep[u] = deep[fa] + 1;
if(diam < deep[u]) {
diam = deep[u];
root = u;
}
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
dfs(v, u, diam, root);
}
}
int main(){
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d%d%d%d", &n, &a, &b, &da, &db);
for(int i = 1; i <= n; i++) G[i].clear();
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
diam = 0;//直径
root1 = 0, root2 = 0;
dfs(b, 0, diam, root1);
dist = deep[a] - deep[b];//在第一个dfs之后
dfs(root1, 0, diam, root2);
diam--;
if(dist > da && db >= 2 * da + 1 && diam >= 2 * da + 1)
printf("Bob\n");
else printf("Alice\n");
}
}