A
dd在玩數字游戲,首先他拿到一個x
當x不為零時進行如下操作
如果二進制x中有奇數個1,則x二進制形式下最低位取反(即0變成1,1變成0)
如果二進制x中有偶數個11,則x二進制形式下非前導零最高位取反
詢問對於一個x,操作幾次后變為零
大力討論即可
#include <iostream>
using namespace std;
int T, x;
int cnt(int x) {
int res = 0;
while (x) {
x -= x & -x;
res++;
}
return res;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &x);
if (!x) {
puts("0");
continue;
}
int n = cnt(x >> 1), m = x & 1;
if ((n + m) % 2 == 1) {
if ((m == 0 && (n % 2 == 0)) || (m == 1 && (n % 2 == 1))) printf("%d\n", 2 * n);
else printf("%d\n", 2 * n + 1);
}
else {
if ((m == 0 && (n % 2 == 0)) || (m == 1 && (n % 2 == 1))) printf("%d\n", 2 * n);
else printf("%d\n", 2 * n - 1);
}
}
return 0;
}
B
dd在玩跳格子游戲,具體游戲規則如下,
n個格子呈環形分布,順時針方向分別標號為1∼n,其中1和n相鄰,每個格子上都有一個正整數a[i],玩家可以選擇一個點作為起點開始跳n下,第i次跳躍,玩家只可以選擇當前位置左邊或右邊最近且尚未被跳躍過的位置進行一次跳躍,並獲得i×a[p]的得分,其中p為第i次跳躍的位置。
dd很雞賊,想贏又不想動腦子,她希望你能給她規划路線以確保她的勝利
考慮逆推:
設f[l][r]為從[l,r]中一點開始,跳完區間[l,r]的最大得分,那么顯然
f[l][r] = max(f[l+1][r] + i * a[l], f[l][r-1] + i * a[r]);
其中i為區間的長度
對環形的處理:令a[i+n]=a[i],枚舉區間[i,i+n-1]取最大值即可
似乎記憶化搜索很好寫qwq
#include <iostream>
using namespace std;
const int maxn = 4e3 + 10;
int n, a[maxn];
int f[maxn][maxn]; //記憶化搜索
int dp(int l, int r) {
if (l == r) return a[l];
if (f[l][r]) return f[l][r];
int i = r - l + 1;
return f[l][r] = (max(dp(l + 1, r) + i * a[l], dp(l, r - 1) + i * a[r]));
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i + n] = a[i];
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, dp(i, i + n - 1));
printf("%d", ans);
return 0;
}
C
首先注意到>=k一定包含了等於k的情況,因此只需判斷是否存在長度為k的相同子串即可
我們可以開兩個bool數組分別記錄x和y的某個k位子串存不存在,然后暴力枚舉即可
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int n, k, ans;
int b1[10000], b2[10000], t[10000];
void ins(int x, int b[]) {
memset(b, 0, sizeof(int) * (1 << k + 1));
int cnt = 0;
while (x) {
t[++cnt] = x & 1;
x >>= 1;
}
for (int i = 1; i * 2 <= cnt; i++) swap(t[i], t[cnt - i + 1]);
for (int i = 1; i + k - 1 <= cnt; i++) {
int p = 0;
for (int j = i; j <= i + k - 1; j++) {
p <<= 1;
p += t[j];
}
b[p] = 1;
}
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 2; i <= n; i++) {
for (int j = 1; j < i; j++) {
if ((int)log2(i) + 1 < k || (int)log2(j) + 1 < k) continue;
ins(i, b1);
ins(j, b2);
bool flag = false;
for (int p = 0; p < (1 << k); p++) {
if (b1[p] && b2[p]) {
flag = true;
break;
}
}
ans += flag;
}
}
printf("%d", ans);
return 0;
}
D
DD給了dd一個由小寫英文字母組成的字符串,但是dd覺得這個串太丑,dd覺得一個優美的字符串應該滿足任意相鄰字符都不相等,她想知道把給定字符串變成一個優美的字符串最少需要插入多少個字符,你只要告訴她,插入最少字符后的串的長度
簽到題
#include <iostream>
#include <cstring>
using namespace std;
int T;
char s[100007];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%s", s);
int ans = strlen(s);
for (int i = 0; s[i] != '\0'; i++) {
if (i > 0 && s[i] == s[i - 1])
ans++;
}
printf("%d\n", ans);
}
return 0;
}
E
dd當上了宣傳委員,開始組織迎新晚會,已知班里有n個同學,每個同學有且僅有一個擅長的聲部,把同學們分成恰好m組,為了不搞砸節目,每一組里的同學都必須擅長同一個聲部,當然,不同組同學擅長同一個聲部的情況是可以出現的,畢竟一個聲部也可以分成好幾個part進行表演,但是他不希望出現任何一組的人過多,否則可能會導致場地分配不協調,也就是說,她希望人數最多的小組的人盡可能少,除此之外,對組內人員分配沒有其他要求,她希望你告訴她,這個值是多少,如果無法順利安排,請輸出-1
經典二分答案
注意:
當越大越容易滿足條件,求第最小的一個時
while (l < r) {
int mid = (l + r) / 2;
if (check(mid)) r = mid; else l = mid + 1;
}
當越小越容易滿足條件,求最大的一個時
while (l < r) {
int mid = (l + r + 1) / 2;
if (check(mid)) l = mid; else r = mid - 1;
}
本題代碼
#include <iostream>
using namespace std;
const int maxn = 2e5 + 10;
int n, m, cnt, a[maxn], b[maxn], l = 1, r;
int ceil(int x, int y) {
if (x % y == 0) return x / y;
else return x / y + 1;
}
bool check(int x) {
int res = 0;
for (int i = 1; i <= n; i++) res += ceil(b[i], x);
return res <= m;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[a[i]]++;
if (b[a[i]] == 1) cnt++;
r = max(r, b[a[i]]);
}
if (cnt > m) {
printf("-1");
return 0;
}
while (l < r) {
int mid = (l + r) / 2;
if (check(mid)) r = mid; else l = mid + 1;
}
printf("%d", l);
return 0;
}
F
被我用BFS水過了。。。
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1e4 + 10;
#define pos first
#define step second
bool vis[maxn];
int n, a[maxn];
queue<pair<int, int> > q;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
if (a[1] > 0) {
for (int i = 1 + 1; i <= 1 + a[1] && i <= n; i++) {
q.push({i, 1});
}
} else {
printf("-1");
return 0;
}
vis[1] = true;
while (!q.empty()) {
pair<int, int> u = q.front(); q.pop();
if (u.pos == n) {
printf("%d", u.step);
return 0;
}
if (vis[u.pos]) continue;
vis[u.pos] = true;
if (u.pos + a[u.pos] < 1) continue;
if (a[u.pos] > 0) {
if (u.pos + a[u.pos] >= n) {
printf("%d", u.step + 1);
return 0;
}
for (int i = u.pos + 1; i <= u.pos + a[u.pos] && i <= n; i++) {
q.push({i, u.step + 1});
}
} else {
for (int i = 1; i <= u.pos + a[i]; i++) {
q.push({i, u.step + 1});
}
}
}
printf("-1");
return 0;
}
G
簡單的雙指針
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 2e6 + 10;
int n, p, a[maxn];
int main() {
scanf("%d%d", &n, &p);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
p = p * 2;
int r = 1, ans = 0;
for (int l = 1; l <= n; l++) {
while (a[l] + p >= a[r] && r <= n) r++;
ans = max(ans, r - l);
if (r > n) break;
}
printf("%d", ans);
return 0;
}
H
給定一個有n個元素的多重集S,有m個詢問,對於每個詢問,給出一個整數x,問是否能選擇S的一個非空子集,滿足這個子集的gcd等於x,當集合只有一個數時,設這個集合的gcd就等於這個數。
對於給定的x,我們在S中選擇的數一定是x的倍數,而且選得越多,它們的gcd越有可能是x
用gcdx[x]表示把選出x的所有倍數進行gcd的結果,如果gcdx[x]等於x,則可以選出gcd等於x的集合
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 2e6 + 10;
int gcd(int x, int y) {
return y ? gcd(y, x % y) : x;
}
int T, n, m;
int a[maxn];
int gcdx[maxn];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
memset(gcdx, 0, sizeof(int) * (n + 1));
memset(a, 0, sizeof(int) * (n + 1));
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
a[x] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
if (a[j]) gcdx[i] = gcd(gcdx[i], j);
}
}
while (m--) {
int x;
scanf("%d", &x);
gcdx[x] == x ? printf("YES\n") : printf("NO\n");
}
}
return 0;
}
注意這個循環,根據調和級數,其復雜度為n*ln(n)
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j += i) {
if (a[j]) gcdx[i] = gcd(gcdx[i], j);
}
}
I
注意到n不超過10,next_permutation即可
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 20;
int n, ans, a[maxn], p[maxn];
bool check() {
for (int i = 1; i <= n; i++) {
if (a[p[i]] == p[i]) continue;
for (int j = 1; j < i; j++)
if (p[j] == a[p[i]]) return false;
}
return true;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), p[i] = i;
do {
if (check()) ans++;
} while (next_permutation(p + 1, p + 1 + n));
printf("%d", ans);
return 0;
}