A - How Much Does Daytona Cost?
题目描述
给你一个长度为n
的数组和一个整数k
,问是否能选择某个区间,使得k
出现的次数大于其他数出现的次数。
思路:贪心
- 贪心选最短的选择区间为
1
,那么就是k
本身,所以判断k
有没有出现过即可。
public static void solve() throws IOException {
int n = readInt(), k = readInt();
int[] arr = utils.nextIntArray(n);
int f = n + 1, l = 0;
boolean flag = false;
for (int i = 1; i <= n; i++) {
if (arr[i] == k) {
flag = true;
}
}
if (flag) {
printWriter.println("YES");
} else {
printWriter.println("NO");
}
}
B - Aleksa and Stack
题目描述
要求你构造一个长度为n
的数组a
,使得对于任意的 i , ( 3 ≤ i ≤ n ) i,(3 \le i \le n) i,(3≤i≤n) 满足 3 ∗ a i % ( a i − 1 + a i − 2 ) ≠ 0 3 * a_i \% \ (a_{i-1} + a_{i - 2}) \neq 0 3∗ai% (ai−1+ai−2)=0,输出这个数组。
思路:模拟
- 起初的 a 1 + a 2 a_1 + a_2 a1+a2的和只要不为 3 3 3,就可以通过不断让 a i a_i ai自增来构造。
public static void solve() throws IOException {
int n = readInt();
int[] arr = new int[n + 1];
arr[1] = 1; arr[2] = 3;
for (int i = 3; i <= n; i++) {
int t = arr[i - 1] + 1;
while (3 * t % (arr[i - 1] + arr[i - 2]) == 0) {// 模为 0就继续自增
t++;
}
arr[i] = t;
}
for (int i = 1; i <= n; i++) {
printWriter.print(arr[i] + " ");
}
printWriter.println();
}
C - Vasilije in Cacak
题目描述
给你三个整数n
,k
,x
,问是否能在 1 ∼ n 1 \sim n 1∼n中选择k
个不通整数来使得它们的和为x
,如果可以输出YES
,否则输出NO
。
输入样例
5 3 10
输出样例
YES
思路:数学(等差数列求和)
- 只要判断这个数
x
是否处于 1 ∼ k 1 \sim k 1∼k的和与 ( n − k + 1 ) ∼ n (n - k + 1) \sim n (n−k+1)∼n的和之间即可,如果这k
个数的和大了,就可以选择一个小的数来替换,如果小了,就可以选择一个大的数来替换,最终一定可以让k
个数的和为x
。例如样例起初选择 1 , 2 , 3 1,2,3 1,2,3 三个数,发现和小了,那么可以用 5 5 5 来替换 1 1 1。
public static void solve() throws IOException {
int n = readInt(), k = readInt();
long x = readLong();
if (x >= 1l * (1 + k) * k / 2 && x <= 1l * (n - k + 1 + n) * k / 2) {
printWriter.println("YES");
} else {
printWriter.println("NO");
}
}
E - Iva & Pav
题目描述
给你一个长度为n
的数组a
,现在定义 f ( l , r ) = a l & a l + 1 & . . . & a r f(l,r)= a_l \& a_{l+1} \& ... \& a_r f(l,r)=al&al+1&...&ar,并且给你q
个查询,对于每个查询,给你一个整数l
和k
,找到最大的r
使得 f ( l , r ) ≥ k f(l,r) \ge k f(l,r)≥k,如果找不到,输出-1
。
思路:线段树+二分+位运算
- 定义
inf
为一个极大数再-1
,这样可以让inf
的每一位都为1
,这样初始化tree
数组全为inf
能保证node
节点的子节点异或后的正确性。- 二分找到最大的
r
,使得 f ( l , r ) ≥ k f(l,r) \ge k f(l,r)≥k。
static int n, m, inf = (1 << 30) - 1;
static int[] tree, arr;
public static void solve() throws IOException{
n = readInt();
arr = new int[n];
tree = new int[n * 4];
for (int i = 0; i < n; i++) arr[i] = readInt();
for(int i = 0 ; i <= n * 4 - 1; ++i) tree[i] = inf;
build(0, 0, n - 1);
m = readInt();
while (m-- > 0) {
int l = readInt() - 1, k = readInt();
int le = l - 1, ri = n;
// 二分找到最大的 r
while (le + 1 < ri) {
int mid = le + ri >> 1;
if (query(0, 0, n - 1, l, mid) >= k) {
le = mid;
} else {
ri = mid;
}
}
// 查询是否存在 f[l,le] >= k
if (query(0, 0, n - 1, l, le) >= k && le != l - 1) {
printWriter.print(le + 1 + " ");
} else {
printWriter.print(-1 + " ");
}
}
printWriter.println();
}
public static void build(int node, int l, int r) {
if (l == r) {
tree[node] = arr[l];
return;
}
int mid = (l + r) / 2;
int leftNode = node * 2 + 1, rightNode = node * 2 + 2;
build(leftNode, l, mid);
build(rightNode, mid + 1, r);
tree[node] = tree[leftNode] & tree[rightNode];
}
public static int query(int node, int l, int r, int s, int e) {
if (l == r || l >= s && r <= e) {
return tree[node];
}
int mid = (l + r) / 2;
int leftNode = node * 2 + 1, rightNode = node * 2 + 2;
int res = inf;
if (mid >= s) {
res &= query(leftNode, l, mid, s, e);
}
if (mid < e) {
res &= query(rightNode, mid + 1, r, s, e);
}
return res;
}