赞
踩
除去 1 1 1 的数均计入
时间复杂度 O ( n ) O(n) O(n)
int solve() {
cin >> n;
int c1 = 0;
for (int i = 0; i < n; i ++) cin >> a[i], c1 += a[i] == 1;
return n - c1;
}
因为不能删除连续的俩字符,故只有八种子串通过操作能够变成 m y g o mygo mygo
mygo, m_ygo, my_go, myg_o, m_y_go, m_yg_o, my_g_o, m_y_g_o
匹配子串,子串内部删除一定,只要看子串左右两侧
可以发现对于长度为 i i i 的串,删除方式数为斐波那契数列
f [ 0 ] = 1 , f [ 1 ] = 2 f [ i ] = f [ i − 1 ] + f [ i − 2 ] , x ≥ 3 f[0]=1,f[1]=2\\f[i]=f[i-1]+f[i-2],~x\ge3 f[0]=1,f[1]=2f[i]=f[i−1]+f[i−2], x≥3
即对于当前字符能删,则从 f [ i − 2 ] f[i-2] f[i−2] 转移而来
不删,则由 f [ i − 1 ] f[i-1] f[i−1] 转移而来
int f[N]; int solve() { cin >> s; n = s.size(); f[0] = 1, f[1] = 2; for (int i = 2; i <= n; i ++) f[i] = ((ll)f[i - 1] + f[i - 2]) % mod; int res = 0; for (int i = 0; i < n; i ++) if (s[i] == 'm') for (int j = i + 1; j <= i + 2; j ++) if (s[j] == 'y') for (int k = j + 1; k <= j + 2; k ++) if (s[k] == 'g') for (int l = k + 1; l <= k + 2; l ++) if (s[l] == 'o') res = ((ll)res + (ll)f[i] * f[n - 1 - l] % mod) % mod; return res; }
贪心的加入 0 0 0,使得一个数两侧的 0 0 0 的个数小于该数
注意头尾边界
时间复杂度 O ( n ) O(n) O(n)
ll solve() {
cin >> n;
for (int i = 0; i < n; i ++) cin >> a[i];
a[n] = 2e9;
ll res = a[0] - 1;
int t = res;
for (int i = 0; i < n; i ++) {
int x = min(a[i] - t, a[i + 1]) - 1;
res += x;
t = x;
}
return res;
}
当 n n n 为偶数时,只要选定 k = n k=n k=n 进行有限次操作,最终肯定符合非降序
当 n n n 为奇数时,因为只能操作偶数位,而末尾为奇数位,因此应当尽可能让后面的数更大,但不超过这个数后面的数
尽可能往上加,因为进行该操作不会影响该位置后面的数,也不会让该数前面的数更不符合条件(相对地)
操作的本质是区间相邻两数之差加一
时间复杂度 O ( n ) O(n) O(n)
string solve() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
if (n & 1 ^ 1) return yes;
ll cnt = 0;
for (int i = n - 1; i >= 1; i --) {
a[i + 1] += cnt;
if (a[i] > a[i + 1]) return no;
if (i & 1 ^ 1) cnt += (a[i + 1] - a[i]) / i;
}
return yes;
}
在贪心可以的前提下,答案为最大的 a i − a i + 1 a_i-a_{i+1} ai−ai+1
ll solve() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
ll cnt = 0, res = 0;
for (int i = n - 1; i >= 1; i --) {
res = max(res, a[i] - a[i + 1]);
if (n & 1 ^ 1) continue;
a[i + 1] += cnt;
if (a[i] > a[i + 1]) return -1;
if (i & 1 ^ 1) cnt += (a[i + 1] - a[i]) / i;
}
return res;
}
本题也可以使用暴力 O ( n 2 ) O(n^2) O(n2) 的筛法, c o d e code code 部分为欧拉筛 O ( n ) O(n) O(n)
构造方法为找到比当前剩余 1 ∼ n 1\sim n 1∼n 数还大的第一个质数 p p p,则可以有一段连续的序列 p − n , p − n + 1 , ⋅ ⋅ ⋅ , n − 1 , n p-n,~p-n+1,~···,~n-1,~n p−n, p−n+1, ⋅⋅⋅, n−1, n,保证长度为偶数,因此可以两两相加,它们的和均为 p p p,然后更新 n : = p − n − 1 n:=p-n-1 n:=p−n−1
如果最后剩余一个数 1 1 1,因为 1 + 1 = 2 1+1=2 1+1=2 也为偶数,因此可以保证上述做法是正确的,也得出结论不存在无解情况
时间复杂度 O ( n ) O(n) O(n)
int cnt, p[N]; bool vis[N]; void getPrimes(int n = 2e3) { for (int i = 2; i <= n; i ++) { if (!vis[i]) p[cnt ++] = i; for (int j = 0; p[j] <= n / i; j ++) { vis[i * p[j]] = true; if (i % p[j] == 0) break; } } } void solve() { cin >> n; m = n; while (n >= 1) { int pr = *upper_bound(p, p + cnt, n); for (int i = pr - n; i <= n; i ++) a[i] = pr - i; n = pr - n - 1; } for (int i = 1; i <= m; i ++) cout << a[i] << ' '; cout << endl; }
本题 n = 1 0 6 n=10^6 n=106 仅可使用欧拉筛,构造方法同 G G G,依然不存在无解情况
时间复杂度 O ( n ) O(n) O(n)
int cnt, p[N]; bool vis[N]; void getPrimes(int n = 2e6) { for (int i = 2; i <= n; i ++) { if (!vis[i]) p[cnt ++] = i; for (int j = 0; p[j] <= n / i; j ++) { vis[i * p[j]] = true; if (i % p[j] == 0) break; } } } void solve() { cin >> n; m = n; while (n >= 1) { int pr = *upper_bound(p, p + cnt, n); for (int i = pr - n; i <= n; i ++) a[i] = pr - i; n = pr - n - 1; } for (int i = 1; i <= m; i ++) cout << a[i] << ' '; cout << endl; }
判断 T , A , 原点 O T,~A,~原点~O T, A, 原点 O 的相对关系
时间复杂度 O ( 1 ) O(1) O(1)
ll solve() {
cin >> t >> a >> k;
if (0 <= a && a <= t || t <= a && a <= 0) return abs(t);
if (0 <= t && t <= a || a <= t && t <= 0) return abs(a) + abs(t - a);
if (a >= -k && a <= k) return abs(a) + abs(t - a);
return abs(t) + 2 * abs(t - a);
}
最开始一段区间合并,只剩一个数为止。后面只需要贪心的取最小变化即可
时间复杂度 O ( n ) O(n) O(n)
ll solve() { cin >> n; for (int i = 0; i < n; i ++) cin >> a[i] >> b[i]; int l = 1, r = 1e9; ll res = 0; for (int i = 0; i < n; i ++) { if (a[i] >= r) { res += a[i] - r; l = r = a[i]; } else if (b[i] <= l) { res += l - b[i]; l = r = b[i]; } else { l = max(l, a[i]); r = min(r, b[i]); } } return res; }
问题可以简化成用 n n n 个物品填满 n − 1 n-1 n−1 的背包空间,因为第一步只能为花费 p p p 并通知一个人,注意该操作也可以多次使用
而题述操作二限制条件为前提是第 i i i 个人已经被通知过,而 b i ≥ 1 b_i\ge 1 bi≥1,故可以贪心的每次都为下一次铺垫(即一定取也可以取下一次操作用到的人)
完全背包,稍微改改就能用
时间复杂度 O ( n 2 ) O(n^2) O(n2)
int f[N];
int solve() {
cin >> n >> m;
for (int i = 0; i < n; i ++) cin >> a[i] >> b[i];
for (int i = 1; i < n; i ++) f[i] = i * m;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n - 1; j ++) {
int u = min(j + b[i], n - 1);
f[u] = min(f[u], f[j] + a[i]);
}
return f[n - 1] + m;
}
时间复杂度 O ( 1 ) O(1) O(1)
void solve() {
cin >> n >> m;
int x = n + m >> 1, y = n - m >> 1;
if (n + m & 1) cout << -1 << endl;
else cout << x << ' ' << y << endl;
}
若存在以下情况,答案为 1 1 1
X 1 X X -> X X X
X 1 X X X X X
X X 1 X -> X X X
X 1 X X X X X
排除以上情况后,
若 n = 1 n=1 n=1 或 n = 2 n=2 n=2 则均无答案
n = 1
1
1
n = 2
1 2
1 2
n ≥ 5 n\ge 5 n≥5 时,可以构造删除第三列元素,始终符合
X X 1 X X X
X X 2 X X X
当 n = 3 n=3 n=3 或 n = 4 n=4 n=4,通过枚举法发现,答案也为 2 2 2
时间复杂度 O ( 1 ) O(1) O(1)
int solve() {
cin >> n;
map<int, int> A, B;
for (int i = 1; i <= n; i ++) cin >> a[i], A[a[i]] = i;
for (int i = 1; i <= n; i ++) cin >> b[i], B[b[i]] = i;
a[n + 1] = b[n + 1] = 0;
int cnt = 0;
for (int i = 1; i <= n; i ++) {
if (a[i] == b[i] && i != 1 && i != n) return 1;
if (a[i] == b[i + 1] || a[i + 1] == b[i]) return 1;
if (a[i] == b[i]) cnt ++;
}
if (n <= 2) return -1;
return 2;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。