AtCoder Beginner Contest 347
B - Substring
难度: ⭐
题目大意
给你一个由小写英文字母组成的字符串S; 请问S有多少个不同的非空子串?
解题思路
数据很小, 暴力就行;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res = inf;
set<string> st;
signed main(){
IOS;
string s;
cin >> s;
for(int i = 0; i < s.size(); i++){
for(int j = 1; i + j <= s.size(); j++){
string str = s.substr(i, j);
st.insert(str);
}
}
cout << st.size();
return 0;
}
C - Ideal Holidays
难度: ⭐⭐⭐
题目大意
小莫的一周有A + B天, 前A天是假期, 后B天是工作日; 小莫有n个计划, 第i个计划安排在第Di天后; 但是小莫忘了今天是这周的第几天, 请问小莫有可能完成这些计划吗;
解题思路
首先我们先把所有Di对(A + B)取余后排序; 我们画一个由A + B + A组成的坐标轴, 小莫的位置在前A + B中, 设为pos, 那么这些任务就分布在pos到(A+B+C); 然后我们可以分类讨论了;
首先我们可以用最晚的任务减去最早的任务时间, 看是否小于等于A, 这样小莫既可以在第一个A的开头, 也可以在中间B的末尾;
如果不满足上述条件, 那么小莫就只能在第一个A的时间里, 并且由于时间跨度大于A, 那么也就是这样任务一定会跨越时间B, 也就是说有两个相邻任务之间的间隔要大于等于B;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res;
int A, B;
int p[N];
bool check(){
sort(p + 1, p + 1 + n);
int len = p[n] - p[1] + 1;
if(len <= A) return true;
for(int i = 2; i <= n; i++){
if(p[i] - p[i - 1] - 1 >= B) return true;
}
return false;
}
signed main(){
IOS;
cin >> n >> A >> B;
bool f = false;
for(int i = 1; i <= n; i++){
cin >> p[i];
p[i] %= (A + B);
}
if(check()) cout << "Yes";
else cout << "No";
return 0;
}
D - Popcount and XOR
难度: ⭐⭐⭐
题目大意
给定数字a, b, C; 要求找出数字x, y; 要求x二进制中1的个数为a, y二进制中1的个数为b, x异或y的结果是C;
解题思路
因为a, b的范围都小于等于60, C也小于等于2的60次方; 所以我们按位遍历C, 如果某一位上为1, 那么我们就贪心地看a和b谁多就把谁的这一位赋为1; 这样结束后剩下的a和b一定是相等的, C此时所有位上的1都被处理的, 剩下的都是0, 自然要求剩下x和y在这些位上的数字相同; 如果此时a和b不为0, 那么我们遍历位数, 如果x和y的这一位都是0, 那么我们就把这些都改为1即可;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
int p[N];
signed main(){
IOS;
cin >> n >> m >> k;
int a = 0, b = 0;
int cnt = 1;
bool f = true;
while(k){
if(k & 1){
if(n > m){
a += cnt;
n--;
}
else {
b += cnt;
m--;
}
if(n < 0 || m < 0){
f = false;
break;
}
}
cnt *= 2;
k >>= 1;
}
if(n != m) f = false;
for(int i = 0; i < 62 && n; i++){
if(!(a >> i & 1) && !(b >> i & 1)){
a |= 1ll << i;
b |= 1ll << i;
n--, m--;
}
}
if(n || m) f = false;
if(f) cout << a << ' ' << b;
else cout << -1;
return 0;
}
E - Set Add Query
难度: ⭐⭐⭐(⭐)
题目大意
现有一个集合S和一个长度为n的空数组A, |S|表示集合S中元素的个数; 现在进行Q次操作, 每次给出一个整数x, 如果S中有x, 那么就删除x, 否则就添加x; 然后对于S中的每个数t, 让At加上|S|;
解题思路
因为数据范围较大, 所以要考虑用O(n)的方式解决; 首先我们记录每次操作后的|S|, 然后记录其前缀和; 而对于每次操作给出的x, 我们要记录其在集合S中存在了多久, 然后用前缀和一次性地添加; 当添加x时, 我们记录x的st, 然后删除时间就是x的ed, 并且在删除时就可以结算了;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, k;
set<int> s;
int p[N], sum[N];
struct node{
int st, ed;
}f[N];
signed main(){
IOS;
cin >> n >> m;
for(int i = 1; i <= m; i++){
int a;
cin >> a;
if(s.count(a)){
s.erase(a);
p[a] += sum[i - 1] - sum[f[a].st - 1];
f[a].st = 0;
}
else {
s.insert(a);
f[a].st = i;
}
sum[i] = sum[i - 1] + s.size();
}
for(int i = 1; i <= n; i++){
if(f[i].st){
p[i] += sum[m] - sum[f[i].st - 1];
}
cout << p[i] << ' ';
}
return 0;
}