有一说一这套题感觉有点差劲 打完之后感觉没有什么提高 全是结论题
A. The Miracle and the Sleeper
题意: 给出一个l, r区间从中要选择a和b 使得 a mod b 最大
贪心 很容易的可以想到当l, r区间足够大的时候 b = a / 2 + 1 (a = r)的时候 a mod b取最大值 当l > r / 2 + 1的时候就b无法取到r / 2 + 1了 则直接r mod l 即可
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int l, r;
cin >> l >> r;
if (l == r) cout << 0 << endl;
else if (l <= r / 2)
{
int x = r / 2;
if (r == x * 2) cout << x - 1 << endl;
else cout << x << endl;
}
else cout << r - l << endl;
}
signed main()
{
int t;
cin >> t;
while (t -- )
{
solve();
}
return 0;
}
B. Scenes From a Memory
给出一串很长的只包含数字的字符串 让我们从中删除最多的数使得删完之后的数为合数 剩下最后一位的时候 1也符合题意 贪心的想 总之最后肯定就只剩下一位数或者两位数 我们可以先用素数筛把所有100之内的素数筛掉 然后判断一位的是否有符合题意的 没有的话再判断两位的
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110;
int prime[N], cnt;
bool st[N];
void init()
{
st[1] = true;
for (int i = 2; i <= N; i ++ )
{
if (!st[i]) prime[cnt ++ ] = i;
for (int j = 0; prime[j] * i <= N; j ++ )
{
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
void solve()
{
int n, ans;
string s;
cin >> n >> s;
int flag = 0;
for (int i = 0; i < n; i ++ )
if (st[s[i] - '0'])
{
ans = s[i] - '0';
flag = 1;
break;
}
if (!flag)
for (int i = 0; i < n; i ++ )
for (int j = i + 1; j < n; j ++ )
{
int a = s[i] - '0', b = s[j] - '0';
if (st[a * 10 + b])
{
ans = a * 10 + b;
flag = 2;
break;
}
}
cout << flag << endl << ans << endl;
}
signed main()
{
int t;
cin >> t;
init();
while (t -- )
{
solve();
}
return 0;
}
C. Rings
给出一串01序列 然后从中筛选出两个子序列 s1 s2 (两序列的长度不能小于原序列总长度 / 2)使得这两个序列由二进制转化为十进制可以满足 f[s1] = f[s2] * k 其中k为正整数
我们可以假设k=1 即变为求 f[s1] = f[s2]怎么取了
那么对于一个不含0的01序列 例如11111 我们可以从第一位取到第三位 再从第三位取到第五位 即只要两序列1个数相同则满足题意
若对于一个含0的呢? 比如100111101 我们可以遍历一遍 找0的位置 如果0在n/2前面 则我们往后取 一直取到最后即原序列的长度n处 使得s1包含这个0 s2不包含这个0 但从0往后的所有位都相等 很明显 f[s1]=f[s2]
如果0在后面呢 我们依然可以这样取 不过要变为反方向 因为某个数乘以2 即左移一位 后面加0 依然可以f[s1] = f[s2]
** 代码**
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110;
int prime[N], cnt;
bool st[N];
void init()
{
st[1] = true;
for (int i = 2; i <= N; i ++ )
{
if (!st[i]) prime[cnt ++ ] = i;
for (int j = 0; prime[j] * i <= N; j ++ )
{
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
void solve()
{
int n, m;
string s;
cin >> n >> s;
m = n / 2;
bool flag = 0;
for (int i = 0; i < n; i ++ )
if (s[i] == '0')
{
flag = true;
if (i < m)
cout << i + 1 << ' ' << n << ' ' << i + 2 << ' ' << n << endl;
else
cout << 1 << ' ' << i + 1 << ' ' << 1 << ' ' << i << endl;
break;
}
if (!flag) cout << 1 << ' ' << m << ' ' << m + 1 << ' ' << m * 2 << endl;
}
signed main()
{
int t;
cin >> t;
while (t -- )
{
solve();
}
return 0;
}
D1. Two Hundred Twenty One (easy version)
题意 : 给出一串序列 只包含 ‘+’ ‘-’ 然后某序列的值为先加后减加减相错 即a1 - a2 + a3 - a4 + a5 … 给出m组询问 问某l, r区间内最少删除几个可以使得此区间和为0
我们考虑这样一个问题 如果我们删掉中间的某个字符会带来什么影响
删掉中间某个字符会使后面所有字符的值变为相反数 那么我们用前缀和来维护从1到n的总和
分类讨论 :
当区间个数为奇数个的时候 假如值为1或-1 我们可以删掉最后一个或者第一个 当值的绝对值>1的时候我们可以删掉中间的一个数 使得后面自区间的值变为前面自区间值的相反数
当区间个数为偶数时也同理 假如值为0 我们可以不删 假如不为0 删掉最后一个将其变为奇数个数 再从中间删掉一个
所以说答案肯定为 0 1 2 分类讨论即可
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10;
int sum[N];
void solve()
{
memset(sum, 0, sizeof sum);
int n, m;
char s[N];
cin >> n >> m >> s + 1;
for (int i = 1; i <= n; i ++ )
{
int x;
if (s[i] == '+')
{
if (i & 1) sum[i] = sum[i - 1] + 1;
else sum[i] = sum[i - 1] - 1;
}
else
{
if (i & 1) sum[i] = sum[i - 1] - 1;
else sum[i] = sum[i - 1] + 1;
}
}
while (m -- )
{
int l, r;
cin >> l >> r;
if ((r - l + 1) & 1) puts("1");
else
{
int cnt = sum[r] - sum[l - 1];
if (cnt) puts("2");
else puts("0");
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t -- )
{
solve();
}
return 0;
}
D2. Two Hundred Twenty One (hard version)
D1的hard版 不止要求需要去掉几个数字了还要求删掉的那些
对于删除思路 当区间为奇时要删掉x处 且sum[x - 1] - sum[l - 1] = sum[r] - sum[x] 当区间为偶时随便删一处(这里我们删掉 l 处的值) 然后按照奇数方法去做
我们已知 sum[x - 1] - sum[l - 1] = sum[r] - sum[x] 可以推导出 sum[r] + sum[l - 1] = sum[x] + sum[x - 1] 故我们想到可以用一个vector存储值为sum[x] + sum[x-1]的所有下标 然后二分去找第一个大于等于当前 l 的即可
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 100, INF = 0x3f3f3f3f;
int n, m;
int sum[N];
map<int, vector<int>> node;
int cal(int l, int r)
{
int x = sum[r] + sum[l - 1];
int t = *lower_bound(node[x].begin(), node[x].end(), l);
return t;
}
void solve()
{
char s[N];
node.clear();
cin >> n >> m >> s + 1;
for (int i = 1; i <= n; i ++ )
{
sum[i] = sum[i - 1] + (i & 1 ? 1 : -1) * (s[i] == '+' ? 1 : -1);
node[sum[i] + sum[i - 1]].push_back(i);
}
while (m -- )
{
int l, r;
scanf("%d%d", &l, &r);
if (sum[r] - sum[l - 1] == 0) puts("0");
else if ((r - l + 1) & 1)
{
puts("1");
printf("%d\n", cal(l, r));
}
else
{
puts("2");
printf("%d %d\n", l, cal(l + 1, r));
}
}
}
signed main()
{
int t;
cin >> t;
while (t -- )
{
solve();
}
return 0;
}