《看了受制了》第四十五天,5道题合计279道题
2023年10月19日
Acwing1978 奶牛过马路
题目理解
这个题目和友好城市太像了,那个是排序一下求最长上升子序列,这个排序一下要达到:
- \(P_i\)前面的每一个数都要小于它
- \(P_i\)后面的每一个数都要大于它
所以我们要在\(O(n)\)的复杂度内处理完需要,搞个前缀最大值和前缀最小值
代码实现
typedef pair<int, int> PII;
const int Mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
void solve()
{
int n;
cin >> n;
vector<PII> v(n);
for(int i = 0; i < n; i++)
cin >> v[i].x >> v[i].y;
sort(v.begin(), v.end());
vector<int> p(n), q(n);
int val = -INF;
int res = 0;
for(int i = 0; i < n; i++)
{
val = max(val, v[i].y);
p[i] = val;
}
val = INF;
for(int i = n - 1; i >= 0; i--)
{
val = min(val, v[i].y);
q[i] = val;
}
for(int i = 0; i < n; i++)
if(v[i].y < p[i] || v[i].y > q[i])
res++;
cout << n - res;
return;
}
Acwing1969 品种临近
题目理解
这个题开数组记录一下,品种的下标做差即可。
代码实现
const int N = 1e6 + 10;
int pos[N];
void solve()
{
int n, k;
cin >> n >> k;
int res = -INF;
for(int i = 1; i <= n; i++)
{
int a;
cin >> a;
if(i - pos[a] <= k && pos[a] != 0)
res = max(res, a);
pos[a] = i;
}
if(res >= 0) cout << res << endl;
else cout << -1 << endl;
return;
}
Acwing1987 粉刷栅栏
题目理解
是一个离散化后差分的题。我们本题练习的是用map
来实现离散化。
代码实现
const int N = 1e5 + 10;
int n;
map<int, int> mp; // map有序的
int main()
{
cin >> n;
int x = 0;
for(int i = 1; i <= n; i++)
{
int k;
string s;
cin >> k >> s;
if(s == "R")
{
mp[x]++;
mp[x + k]--;
x += k;
}else{
mp[x - k]++;
mp[x]--;
x -= k;
}
}
int res = 0, sum = 0, last;
for(auto& [x, v] : mp)
{
if(sum >= 2) res += x - last; //
sum += v; // 前缀和
last = x;
}
cout << res;
return 0;
}
Atcoder ABC324 D
题目大意
问一些数字全排列后组成的数字,可以组成几个完全平方数。
题目理解
我们正向枚举的话是\(13!\)这肯定爆了,但是我们可以枚举完全平方数,因为要平方,所以只能到\(1e^7\),完全ok。然后我们统计数字出现的次数是否满足就行了。
代码实现
vector<ll> vec;
int cnt[10];
int a[10];
bool check(ll u)
{
memset(a, 0, sizeof a);
while(u)
{
a[u % 10]++;
u /= 10;
}
for(int i = 1; i <= 9; i++)
if(a[i] != cnt[i])
return false;
return true;
}
int len(ll u)
{
int cnt = 0;
while(u) u /= 10, cnt++;
return cnt;
}
void solve()
{
int n;
string s;
cin >> n >> s;
for(int i = 0; i < n; i++)
cnt[s[i] - '0']++;
int res = 0;
for(int i = 0; i < (int)vec.size(); i++)
{
if(len(vec[i]) > n) break;
if(check(vec[i]))
res++;
}
cout << res;
return;
}
Atcoder ABC324 E
题目大意
给了\(N\)个字符串,两两任意组合,可以选择相同的串组合。问组合的\(N^2\)中可能中,有多少可能,里面的子序列是包含T的。
题目理解
直接枚举肯定爆了。本题学到的知识是字符串子序列的匹配:
- 如果想判断两个串的和\(s_i + s_j\)是否为\(t\)的子序列(不连续的)
- 从左往右匹配看能匹配多少个字符记为\(i\)
- 从右往左匹配看能匹配到多少个字符记为\(j\)
- 只要满足\(i + j >= len(s)\)那么说明肯定\(t\)中包含。
我们有了上述的思想后,我们便可对于\(n\)个串得到\(a和b\)两个数组,分别代表上述的从左往右的数量和从右往左的数量。
那么问题就转化成了:
- 在\(a\)、\(b\)两个序列中有多少组\(a_i + b_j >= len(t)\)
那么二分即可!也可以用那个low_bound,我记得之前那个墙的题做过。
代码实现
vector<ll> vec;
int cnt[10];
int a[10];
bool check(ll u)
{
memset(a, 0, sizeof a);
while(u)
{
a[u % 10]++;
u /= 10;
}
for(int i = 1; i <= 9; i++)
if(a[i] != cnt[i])
return false;
return true;
}
int len(ll u)
{
int cnt = 0;
while(u) u /= 10, cnt++;
return cnt;
}
void solve()
{
int n;
string s;
cin >> n >> s;
for(int i = 0; i < n; i++)
cnt[s[i] - '0']++;
int res = 0;
for(int i = 0; i < (int)vec.size(); i++)
{
if(len(vec[i]) > n) break;
if(check(vec[i]))
res++;
}
cout << res;
return;
}