A.max or min
CF上ac了洛谷wa1?
好神啊不会做
去膜了下官方题解 并跟着写了一发线段树 结果写挂了没调出来
后来换珂朵莉树T爆了
bzy:set维护线段不是很常见的操作吗 你怎么写到100行的
我:。。。。。
做法如下
注意到有意义的只是当前数字与目标数字的大小关系
我们可以令小于当前数字的数全部变成-1 大于则为1 等于为0
考虑以下情况
如果序列是0 1 1 1 或者0 -1 -1 -1 要让他们变成0只要进行(n-(0的个数))次操作即可
如果是0 -1 1 -1 这样的交替序列 如果 -1 1 -1 1 这样的交替序列长为L
我们要先让他们全部变成1或者-1 再全部变成0
于是操作次数就多了L/2向下取整次
我们记sumz为一共要多操作的次数 则答案为n-目标数字的出现次数+sumz
我们要维护每个交替串的起点终点和长度
对于不是环的情况求出sumz 对于是环的情况就可以特判一下1和n位置能不能形成交替串 如果能就更新一下答案
通过set可以在log时间内找出某个位置所属交替串的起点终点
然后我们要实现upd(pos,val)操作 把数组pos的位置修改 为val
注意到val若为-1 则之前pos位置必为0 若val为0 则pos位置之前必为1
这样就可以找出交替串 并且一点一点更改目标数值求出所有答案了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
typedef pair<int, int> pii;
set<pii, less<pii> > s;
#define IT set<pii, less<pii> > :: iterator
int a[maxn], n, m, sumz, ans;
vector<int> _[maxn];
void upd(int pos, int val) {
if (val == 0) { //1改成0
a[pos] = 0;
IT it = s.lower_bound(make_pair(pos, pos));
if (it == s.end() || it->first != pos) it--;
pii u = *it;
s.erase(u);
sumz -= (u.second - u.first + 1) / 2;
if (u.first < pos) {
s.insert(make_pair(u.first, pos-1));
sumz += (pos - u.first) / 2;
}
if (u.second > pos) {
s.insert(make_pair(pos + 1, u.second));
sumz += (u.second - pos) / 2;
}
} else if (val == -1) {//0改-1 接起来两段
a[pos] = -1;
if (pos < n && a[pos + 1] == 1) {
IT it = s.lower_bound(make_pair(pos + 1, pos + 1));
if (it == s.end() || it->first != pos + 1) it--;
pii u = *it;
s.erase(u);
sumz -= (u.second-u.first + 1) / 2;
s.insert(make_pair(pos, u.second));
sumz += (u.second - pos + 1) / 2;
} else s.insert(make_pair(pos, pos));
if (pos > 1 && a[pos - 1] == 1) {
IT it = s.lower_bound(make_pair(pos-1, pos-1)), it2 = s.lower_bound(make_pair(pos, pos));
if (it == s.end() || it->first != pos - 1) it--;
//if (it2 == s.end() || it2->first != pos) it2--;
pii u = *it, v = *it2;
sumz -= (u.second - u.first + 1) / 2;
sumz -= (v.second - v.first + 1) / 2;
s.erase(u);
s.erase(v);
sumz += (v.second - u.first + 1) / 2;
s.insert(make_pair(u.first, v.second));
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
_[a[i]].push_back(i);
a[i] = 1;
s.insert(make_pair(i, i));
}
for (int i = 1; i <= m; i++) {
if (_[i].size() == 0) {
puts("-1");
continue;
}
for (int j = 0; j < _[i].size(); j++) upd(_[i][j], 0);
if (a[1] == 0 || a[n] == 0 || a[1] == a[n]) {
ans = sumz + n - _[i].size();
} else {
IT it = s.lower_bound(make_pair(n, n)), it1 = s.lower_bound(make_pair(1,1));
if (it == s.end() || it->first != n) it--;
//if (it1 == s.end() || it1->first != 1) it1--;
ans = sumz - (it->second-it->first+1)/2-(it1->second-it1->first+1)/2+(it1->second-it1->first+it->second-it->first+2)/2 + n - _[i].size();
}
cout << ans << "\n";
for (int j = 0; j < _[i].size(); j++) upd(_[i][j], -1);
}
}
B.level up
考场没有注意到要通过排序保证正确性
当一个X=u的元素可以使level1的经验溢出时,所有X>=u的元素都可以
我们要想办法遍历所有可以使其溢出的元素 从中选出最优解
那么按x的大小排序再进行背包就行了
dp方程就是个背包 第一维滚动数组滚掉就行
#include<bits/stdc++.h>
//wa 7
//j + e[i].x >= s1要判
//j == s1 要判
using namespace std;
const int maxn = 507;
#define ll long long
#define inf 9999999999999999ll
ll dp[2][maxn][maxn];
ll s1, s2, n;
ll ans;
struct _ {
ll x, t, y, r;
bool operator < (const _ &rhs) const {
return x < rhs.x;
}
}e[maxn];
int main() {
cin >> n >> s1 >> s2;
for (int i = 1; i <= n; i++) {
cin >> e[i].x >> e[i].t >> e[i].y >> e[i].r;
}
sort (e + 1, e + n + 1);
for (int i = 0; i <= s1; i++) {
for (int j = 0; j <= s2; j++)
dp[0][i][j] = dp[1][i][j] = inf;
}
dp[0][0][0] = 0;
for (int i = 1; i <= n; i++) {
dp[(i&1)^1][0][0] = 0;
for (int j = 0; j <= s1; j++) {
for (int k = 0; k <= s2; k++) {
if (j < s1 && j + e[i].x > s1) {
dp[i&1][s1][min(s2,k+j+e[i].x-s1)] = min(dp[i&1][s1][min(s2,k+j+e[i].x-s1)], min(dp[(i&1)^1][j][k]+e[i].t, dp[(i&1)^1][s1][min(s2,k+e[i].x+j-s1)]));
} else if (j + e[i].x <= s1) {
dp[i&1][j+e[i].x][k] = min(dp[i&1][j+e[i].x][k], min(dp[(i&1)^1][j+e[i].x][k], dp[(i&1)^1][j][k]+e[i].t));
}
if (k < s2) {
dp[i&1][j][min(k+e[i].y, s2)] = min(dp[i&1][j][min(k+e[i].y, s2)], min(dp[(i&1)^1][j][k] + e[i].r, dp[(i&1)^1][j][min(k+e[i].y, s2)]));
}
}
}
}
if (dp[n&1][s1][s2] == inf) cout << -1 << endl;
else cout << dp[n&1][s1][s2] << endl;
}
D. Cycle String?
签到题但是我wa19了
分类讨论一下 统计出现次数最多的字符的出现次数 记为mx
如果mx > 2n-2 无论如何都有长为n的重复子串了
如果mx == 2n-2且一共只有2种字符 没有合法的构造方案
如果mx <= n 直接按字典序排序输出即可
如果mx>n且不为上述情况 考虑构造解
我wa33的解的形式应为:先输出n个出现次数最多的字符 然后放一个其他字符 剩下的再输出所有出现次数最多的那个字符 然后剩下的再输出
----------------
wa33破案了
n=1没有特判
是判断的先后顺序出了问题
e.g ab是可以输出的
---------------
然后我wa35了。。。
n=2的情况 abba是合法的
---------------
wa34 这两个东西输出不能直接输出原串。。。
---------------
wa34 n==2的特判也不是按字典序输出 要mx == n才行
---------------
ac
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 7;
int cnt[26], cnta, mx, mxi;
string s;
int main() {
cin >> s;
int l = s.length(), n = l / 2;
for (int i = 0; i < l; i++) {
cnt[s[i] - 'a'] ++;
if (cnt[s[i]-'a'] == 1) cnta++;
if (mx <= cnt[s[i]-'a']) {
mxi = s[i]-'a';
mx = cnt[mxi];
}
}
//printf("%d\n", cnta);
if (n <= 2 && cnta == 2 && mx == n) {
puts("YES");
for (int i = 0; i < 26; i++) {
while (cnt[i]) {
putchar(i+'a');
cnt[i]--;
}
}
return 0;
}
if (mx >= l - 1 || (mx == l - 2 && cnta == 2)) {
puts("NO");
return 0;
} else if (mx <= n) {
puts("YES");
for (int i = 0; i < 26; i++) {
while (cnt[i]) {
putchar(i+'a');
cnt[i]--;
}
}
} else {
puts("YES");
for (int i = 0; i < 26; i++) {
if (i == mxi) continue;
if (cnt[i]) {
putchar(i +'a');
cnt[i]--;
break;
}
}
for (int i = 1; i <= n; i++) {
putchar(mxi+'a');
}
cnt[mxi] -= n;
for (int i = 0; i < 26; i++) {
if (i == mxi) continue;
if (cnt[i]) {
putchar(i +'a');
cnt[i]--;
break;
}
}
while(cnt[mxi]) {
putchar(mxi + 'a');
cnt[mxi]--;
}
for (int i = 0; i < 26; i++) {
//if (i == mxi) continue;
while (cnt[i]) {
putchar(i+'a');
cnt[i]--;
}
}
}
}