2022-04-18每日刷题打卡
代码源——每日一题
真假字符串 - 题目 - Daimayuan Online Judge
给定两个长度相等的字符串 S1,S2, 问能否找出一个字符串 S, 使得 S 只删除一个字符可以得到 S1, 并且 S 只删除一个字符也可以得到 S2 (可以是不同位置的字符)。
输入格式
输入第一行给出字符串 S1, 第二行给出字符串 S2, 两个字符串的长度 1≤len≤300000。
输出格式
如果能找到满足条件的字符串 S, 输出 1, 否则输出 0。
样例输入
abacaa
aacaba
样例输出
1
样例解释
abacaba 删除第二个字符 b 可以得到字符串 S1, 并且删除第一个字符 b 可以得到字符串 S2。
如果题目说的,有一个字符串s可以通过删除一个字符得到s1和s2,那说明要么s1和s2相等(s删除的地方一样),要么说明s1和s2有一处地方不一样(s删除的地方不一样),即我们可以把题目转化成:s1和s2是否可以最多删除一个字符后相等。
我们先遍历一下两个字符串,找第一个不相同的地方,如果没有,说了s1和s2相同,我们直接输出1。如果有不相同的地方,则要分两种情况讨论了:
1、我们删掉s1的一个字符,然后继续比较s1和s2,如果找到下一处地方不一样,就删除s2的一个字符,经过这次删除后如果两个字符串相同了就是1,不然我们就看第二种情况。
2、我们删掉s2的一个字符,然后继续比较s1和s2,如果找到下一处地方不一样,就删除s1的一个字符,经过这次删除后如果两个字符串相同了就是1,反之是0。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
bool dfs(string s1, string s2)
{
int n = s1.size(),l=0,r=0;
bool st = true;
while (l < n && r < n)
{
if (s1[l] != s2[r])
{
if (st)
{
l++;
st = false;
}
else return false;
}
else l++, r++;
}
if (l < n)return false;
return true;
}
int main()
{
string s1, s2;
cin >> s1 >> s2;
int n = s1.size(), ans = -1;
for (int i = 0; i < n; i++)
{
if (s1[i] != s2[i])
{
ans = i;
break;
}
}
if (ans == -1)
{
cout << 1 << endl;
}
else
{
string str1 = s1, str2 = s2;
str1.erase(ans,1);
str2.erase(ans,1);
if (dfs(s2, str1) || dfs(s1, str2))
{
cout << 1 << endl;
}
else cout << 0 << endl;
}
return 0;
}
CodeForces——线段树专题
E - Segment Tree, part 1 - Addition to Segment
There is an array of n elements, initially filled with zeros. You need to write a data structure that processes two types of queries:
add to the segment from l to r−1 the number v,
find the current value of element i.
You may have heard that such requests can be made using the tree of segments with mass change operations (we will talk about it in the next lesson), but this problem can be solved using a regular segment tree.
Input
The first line contains two numbers n and m (1≤n,m≤100000), the size of the array and the number of operations. The following lines contain the description of the operations. The description of each operation is as follows:
1 l r v: add the value v to the segment from l to r−1 (0≤l<r≤n, 0≤v≤109).
2 i: find the value of the element with index i (0≤i<n).
Output
For each operation of the second type, print the corresponding value.
Example
input
5 5
1 0 3 3
2 1
1 2 4 4
2 3
2 4
output
3
4
0
这题是说,给你一个全是0的数组,进行两种操作,一种是在l~r-1区间里全家上数值v,另一种是找到下标为x的值。
用线段树我们可以在logn的复杂度下做到单点修改和区间和计算。但此时是区间修改,如果还是用一般的线段树,那效率是很低的,不如直接用数组。所以这里我们加入了一个新的概念:懒惰标记。
懒惰标记,简单来说,就是通过延迟对节点信息的更改,从而减少可能不必要的操作次数。每次执行修改时,我们通过打标记的方法表明该节点对应的区间在某一次操作中被更改,但不更新该节点的子节点的信息。实质性的修改则在下一次访问带有标记的节点时才进行。
也就是,当我们要在l到r区间的点都加上x时,我们找到管理这些区间的父节点而不是叶子节点,给这个父节点记录上大小为x的懒惰标记,这样当下次我们计算区间和时,就可以根据 懒惰标记*该区间的点数 知道这个区间通过1操作增加了多少总和。加上原本父节点存储的总和,就是我们要的区间总和了。
有了懒惰标记,我们就不用真的给区间的点都加上x,通过计算,我们还是可以通过logn的复杂度完成区间的修改和查询。
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
const int N = 300050;
ll f[4 * N], a[N], n;
void revise(ll k, ll l, ll r, ll x, ll v)
{
if (l == r )
{
f[k] += v;
return;
}
ll m = (l + r) / 2;
if (x <= m)revise(k + k, l, m, x, v);
else revise(k + k + 1, m + 1, r, x, v);
f[k] = f[k + k] + f[k + k + 1];
}
ll calc(ll k, ll l, ll r, ll x, ll y)
{
if (l == x && r == y)
{
return f[k];
}
ll m = (l + r) / 2;
if (y <= m)return calc(k + k, l, m, x, y);
else
if (x > m)return calc(k + k + 1, m + 1, r, x, y);
else return calc(k + k, l, m, x, m) + calc(k + k + 1, m + 1, r, m + 1, y);
}
int main()
{
int t, st;
cin >> n >> t;
while (t--)
{
cin >> st;
if (st == 1)
{
ll x, y, v;
cin >> x >> y >> v;
revise(1, 1, n, x + 1, v);
if (y < n) revise(1, 1, n, y + 1 , -v);
}
else
{
ll x;
cin >> x;
cout << calc(1, 1, n, 1, x + 1 ) << endl;
}
}
return 0;
}