题目链接 题目大意: 有n个人参加投票,小明是第一个; 投票一共k轮,每轮每个人会做出一个选择,分别用+和-表示,那么一共有三个结果: +的人数大于-的人数,那么-的人出局; -的人数大于+的人数,那么+的人出局; 如果+和-的人数一样多,那么所有人出局; 出局的人,不再参与后续投票。
小明有特权,可以在第一轮投票之前淘汰掉若干个人,现在想知道,最终能有多少个人留到了最后;(小明一定保证自己会留到最后)
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤1000) 每个样例n+1行 第一行,整数𝑛 和 𝑘 (1≤𝑛,𝑘≤100) 接下来n行,每行有k个字符,表示每个人都投票结果。
输出: 输出留到最后的人数。
Examples input 5 2 2 ++ +- 1 3 +-+ 4 1
5 4 ++++ +--+ ++-+ +-++ ++++ 4 2 ++ -- -- -+
output 1 1 2 2 1
题目解析: 由于题目不需要选择淘汰的顺序,并且小明一定会留在最后,那么和小明相同的投票结果的人会保留;
class Solution {
static const int N = 201010;
char s[N], r[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
int ans = 1;
cin >> s;
for (int i = 1; i < n; ++i) {
cin >> r;
int tmp = 0;
for (int j = 0; j < k; ++j) tmp += s[j] == r[j];
ans += tmp == k;
}
cout << ans << endl;
}
}
}
题目链接 题目大意: 给出一个由整数和?组成的字符串,其中符号?可以匹配任何单个数字; For example: 42 matches 4?; 1337 matches ????; 1337 matches 1?3?; 1337 matches 1337; 3 does not match ??; 8 does not match ???8; 1337 does not match 1?7.
现在问给出的字符串,最多存在多少个合法的匹配数字;(不包括前导零,整数大于零)
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤20000) 每个样例1行,字符串𝑠 (1≤|𝑠|≤5)
输出: 每个样例一行,输出最多存在多少个合法的匹配数字;
Examples input 8 ?? ? 0 9 03 1??7 ?5? 9??99
output 90 9 0 1 0 100 90 100
题目解析: 分情况讨论: 1、给出的字符串就存在前导零,那么结果为0; 2、给出的字符串合法,并且存在x个?号,那么有两种情况: 2.1,?号之前已经有整数,此时?号可以取任意数字,那么x个?号可以得到10^x个整数; 2.2,?号前面没有整数,此时第一个?号只能取1-9数字,所以会减少10^(x-1)个答案;
class Solution {
static const int N = 201010;
char s[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
cin >> s;
int n = strlen(s);
int x = 0;
for (int i = 0; i < n; ++i) x += (s[i] == '?');
if (s[0] == '0') cout << 0 << endl;
else if (s[0] == '?') {
if (!x) cout << 1 << endl;
else cout << (int)pow(10, x) - (int)pow(10, x - 1) << endl;
}
else {
cout << (int)pow(10, x) << endl;
}
}
}
}
ac;
题目链接 题目大意: 给出一个由n个整数组成的数组a,在数组中选择区间[l, r],将区间内的整数按照非降序进行处理得到整数数组b,比如说: 整数数组a为[6,7,3,4,4,6,5],选择区间[2, 5]得到整数数组b为[6,3,4,4,7,6,5];(区间外的整数位置不变)
现在已知整数数组a和变化后的整数数组b,求区间最长可能为多少?
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例3行: 第一行整数n(2≤𝑛≤2⋅1e5) 第二行整数数组a 第二行整数数组b 注意:数组a和数组b至少有一个位置的元素不相同。
输出: 每个样例一行,输出区间[l, r],表示可以选择进行操作的最长区间,如果由多个答案,输出任意一个;(题目保证有解)
Examples input 3 7 6 7 3 4 4 6 5 6 3 4 4 7 6 5 3 1 2 1 1 1 2 3 2 2 1 2 1 2
output 2 5 1 3 2 3
题目解析: 假如不考虑复杂度,那么应该枚举区间[x, y],然后计算每个区间的可行性,这样复杂度为枚举复杂度 * 验证复杂度,枚举就已经超过题目限制; 注意题目给出的条件,数组a和b有元素不相同,那么至少存在2个位置不相同,否则题目无解; 假定第一个不相同元素的位置是x,最后一个不相同元素的位置是y,那么区间[x, y]必然是一个解,但不是最长解: 假设区间[x, y]右边的元素比区间[x, y]内的元素更大,那么可以纳入到这个区间内,因为排序完无影响; 同理对于区间[x, y]左边的元素,只要小于的等于区间内最小值,那么同意可以纳入到区间中;
注意: 区间外的整数,不一定有序的,比如说: 2 2 4 3 5 4 2 2 3 4 5 4
class Solution {
static const int N = 201010;
int a[N];
int b[N];
public:
void solve() {
int t;
cin >> t;
int cnt = 0;
while (t--) {
int n, x, y = 0;
cnt++;
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
x = -1;
for (int i = 0; i < n; ++i) {
if (a[i] != b[i]) {
if (x == -1) x = i;
else y = i;
}
}
int valMin = b[x], valMax = b[y];
while (x > 0) {
if (b[x - 1] <= valMin) --x;
else break;
valMin = min(valMin, b[x]);
}
while (y < n - 1) {
if (b[y + 1] >= valMax) ++y;
else break;
valMax = max(valMax, b[y]);
}
cout << (x + 1) << " " << (y + 1) << endl;
}
}
}
题目链接 题目大意: 给出一个小写字母组成的字符串s,现在可以对字符串进行多次操作: 选择若干个不相邻的位置,移除这些位置上的字符,剩下的字符保持相对顺序组成新的字符串s;
假如操作若干次后,剩下的字符串都由相同字符组成,最少需要多少次;
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例一行,字符串s;(长度不超过200,000)
输出: 每个样例一行,输出最少的次数。
Examples input 5 abacaba codeforces oooooooo abcdef mewheniseearulhiiarul
output 1 3 0 2 4
12345678
题目解析: 先简化题目,按照题目去掉若干个字符: 去掉字符长度为2,需要2个操作; 去掉字符长度为3,需要2个操作; 去掉字符长度为4,需要3个操作; 去掉字符长度为7,需要3个操作; 去掉字符长度为8,需要4个操作; ... 去除的规则比较简单,每次去除所有奇数位置,就可以最快去除;
题目的要求,最后只剩一种字符,那么结果一共有26种组合。 以字符a为例,遍历一遍字符串,那么就可以得到若干个由a分隔的区间,其中最长的区间假设是x,那么这个区间的移除代价就是最终的移除代价; 同理得到26个字母的结果,取其最小得到结果。
class Solution {
static const int N = 201010;
char s[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
cin >> s;
int n = strlen(s);
int ans = n;
for (int i = 0; i < 26; ++i) {
char c = 'a' + i;
int len = 0, last = -1;
for (int j = 0; j < n; ++j) {
if (s[j] == c) {
last = j;
}
else {
len = max(len, j - last);
}
}
if (len == 0) {
ans = 0;
break;
}
int tmp = 1;
while ((1 << tmp) <= len) ++tmp;
ans = min(ans, tmp);
}
cout << ans << endl;
}
}
}
题目链接 题目大意: 有一排格子排成一行,编号从左到右分别为0、1、2、3; 小明站在第0个格子,每次小明有三个选择可以进行操作: 1、移动到下一个格子:从格子x移动到格子x+1; 2、按下shift按钮; 3、松开shift按钮,小明在按下shift按钮期间经过的格子会被染色;
现在只有若干个区间[x, y]允许染色,区间外的格子不允许染色; 现在想要染色k个格子,问最少需要操作多少次;
1e18
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例3行: 第一行,整数 𝑛 和 𝑘 (1≤𝑛≤2⋅1e5; 1≤𝑘≤1e9) 第二行,整数 𝑙1,𝑙2,…,𝑙𝑛,表示n个区间的起点 (1≤𝑙1<𝑙2<⋯<𝑙𝑛≤1e9) 第三行,整数 𝑟1,𝑟2,…,𝑟𝑛 ,表示n个区间的终点 (1≤𝑟𝑖≤109; 𝑙𝑖≤𝑟𝑖<𝑙𝑖+1−1) n个区间没有重合;
输出: 每个样例一行,输出最少的操作次数,如果无解则输出-1;
Examples input 4 2 3 1 3 1 4 4 20 10 13 16 19 11 14 17 20 2 3 1 3 1 10 2 4 99 999999999 100 1000000000
output 8 -1 7 1000000004
题目解析: 简单策略,小明从左到右,只要经过允许的区间就染色,直到k个格子; 考虑到要最小操作次数,那么同一个区间的染色操作要合并,那么策略可以进行优化: 对于每一个区间,先考虑区间是否小于需要染色数量,是的话则直接染色整个区间; 如果当前区间足够剩余染色数量,则选择需要染色的x个格子即可。 但是这种策略少考虑了一种情况: 以题目样例3为例,假设一种情况是1011111111,其实先选择前面的1,则会花费3的代价(两次shift+1次移动),总的花费是8;如果不选择前面1,而是选择后面位置3开始的1,则只需要花费的代价是7; 为什么会出现这种情况? 因为前面会有2次选中操作,但是后面则只需要1次选中操作,减少了1次选中操作(即是2次shift),虽然多花费了1次move操作,但是总的花费还是减少了1; 所以在这种情况下,简单的策略在以下这种情况: 101010....011111....0110..101010....1111111... 都会难以处理,因为在决策是否要染色时,还可能受到后续方块的影响。
为了简化思考过程,可以我们把移动和选择拆分来看,先假设小明从0开始移动到第i个可以染色区间,小明经过的区间可以分为三类: 1、长度为1区间; 2、第1个到第i-1个区间中,长度大于1的区间; 3、第i个区间;(为什么第i个单独列出来,是因为第i个允许仅染色部分)
移动的代价分为两部分,首先是移动到第i个区间起始位置,另外一个是在第i个区间移动的距离; 选择的代价,首先是长度大于>1的区间,然后是第i个区间,接着是长度为1的区间;
Example: k=10 10101010101010101010111011111111111111 19+2*10=39 20+4+7+4=35
class Solution {
static const int N = 201010;
int a[N], b[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
lld sum = 0, oneCnt = 0;
lld ans = 0xffffffffffff;
for (int i = 0; i < n; ++i) {
lld len = b[i] - a[i] + 1;
if ((sum + len) >= k && k >= (sum - oneCnt)) {
if (sum - oneCnt + len >= k) {
ans = min(ans, a[i] - 1 + (i - oneCnt + 1) * 2 + (k - (sum - oneCnt)));
}
else {
ans = min(ans, a[i] - 1 + (i - oneCnt + 1) * 2 + len + 2 * (k - (sum - oneCnt + len)));
}
}
if (len == 1) ++oneCnt;
sum += len;
}
if (ans == 0xffffffffffff) cout << "-1" << endl;
else cout << ans << endl;
}
}
}