AtCoder Beginner Contest 449 T3,T4,T5,T6题解
C - Comfortable Distance
运行时间限制: 2 秒 / 内存限制: 1024 MiB
分数 : 300 分
问题描述
给定由英文字母小写组成的长度为 N 的字符串 S。
请求满足以下所有条件的整数对 (i, j) 的个数。
- 1≤i≤j≤N
- S_i = S_j
- L≤j−i≤R
限制
2≤N≤5×10^5
1≤L≤R≤N−1
N, L, R 为整数
S 为长度为 N 的英文字母小写组成的字符串
输入
输入以以下格式从标准输入提供。
N L R
S
输出
请输出答案。
输入样例1
6 2 4
aabcba
输出样例1
2
输入样例2
9 3 6
aaaaaaaaa
输出样例2
18
输入样例3
10 2 6
aabbccaabb
输出样例3
6
solve
翻译后
考虑固定 j 来统计答案。如果能够求出满足 j−R ≤ i ≤ j−L 且 S_i = S_j 的 i 的个数就可以了。这可以通过对每个小写字母的出现次数进行前缀和预计算来得到。具体来说,记 A_{c,k} 为前 1,2,…,k 个字符中英文字母 c 的出现次数,那么所求的 i 的个数就是 A_{S_j, max(j−L,0)} − A_{S_j, max(j−R−1,0)}。
上面的解法时间复杂度为 O(σN),其中 σ 为字母种类数量,但也可以在 O(σN) 时间内解决。始终管理 j−R ≤ i ≤ j−L 范围内的 S_i 的频率数组,并按 j=1,2,...,N 的顺序边更新边计算。当 j 增加 1 时,需要统计的范围变化为 O(1)。因此,同时维护整个频率数组并更新,就可以完成计算。下方的实现例子也可以参考。
zyz的解答
对于此题,用前缀和处理各字母出现个数
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
long long n,l,r;
long long s[30][maxn];
char c;
long long ans;
int main()
{
cin >> n >> l >> r;
for (long long i=1;i<=n;i++)
{
cin >> c;
for (long long j=0;j<26;j++) s[j][i]=s[j][i-1];
s[c-'a'][i]=s[c-'a'][i-1]+1;
long long L=max(i-r,(long long)1);
long long R=i-l;
if (R<1) continue;
ans += s[c-'a'][R]-s[c-'a'][L-1];
}
cout << ans << endl;
return 0;
}
D - Make Target 2
运行时间限制: 2 秒 / 内存限制: 1024 MiB
分数 : 425 分
问题描述
在二维坐标平面上,坐标为 (x,y) 的格点,如果 max(|x|,|y|) 为偶数则涂黑,为奇数则涂白。
请计算满足 L≤x≤R 且 D≤y≤U 的整数对 (x,y) 中,被涂成黑色的坐标点的数量。
限制
- $-106$≤L≤R≤$106$
- $-106$≤D≤U≤$106$
- 输入的值都是整数
输入
输入以以下格式从标准输入提供。
L R D U
输出
请输出答案。
输入样例1
-4 3 1 3
输出样例1
10

如上图所示,所求的答案是 10。
输入样例2
-14 14 -14 14
输出样例2
449
solve
翻译后
为了简洁地处理 max(∣x∣,∣y∣) 这个式子,对满足 ∣x∣>∣y∣ 的情况和 ∣x∣≤∣y∣ 的情况进行分类计数,最后将它们相加即可得到答案。
以下介绍一个计算 ∣x∣>∣y∣ 情况数量的例子。∣x∣≤∣y∣ 的数量可以同样方法计算。
当 ∣x∣>∣y∣ 时,max(∣x∣,∣y∣)=∣x∣。因此,对满足 L≤x≤R 且 x 为偶数的所有 x 进行全搜索,对于每一个 x,计算满足 ∣x∣>∣y∣ 且 D≤y≤U 的 y 的个数即可。由于 ∣x∣>∣y∣ 等价于 −∣x∣<y<∣x∣,当 x 固定时,被统计的 y 的范围为 max(−∣x∣+1,D)≤y≤min(∣x∣−1,U)。这个范围内的整数 y 的个数为 max(0,min(∣x∣−1,U)−max(−∣x∣+1,D)+1),可以对每个 x 在 O(1) 时间内计算。因此,∣x∣>∣y∣ 的数量可以视 X=R−L,在 O(X) 时间内计算。
注释:对于max(−∣x∣+1,D)≤y≤min(∣x∣−1,U),我们发现|x|要+1或-1,原因是我们可以通过此方法去掉一些由于在计算|y|时也会计算(即算重)的点(那么在算|y|时就不用+1-1了)
Code
提示:不开long long见祖宗
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
long long l,r,d,u;
long long ans;
int main()
{
cin >> l >> r >> d >> u;
for (long long x=l;x<=r;x++)
{
if (x%2==0)
{
long long D=max(d,-abs(x)+1);
long long U=min(u,abs(x)-1);
long long c=U-D+1;
ans += max(c,(long long)0);
}
}
for (long long y=d;y<=u;y++)
{
if (y%2==0)
{
long long L=max(l,-abs(y));
long long R=min(r,abs(y));
long long c=R-L+1;
ans += max(c,(long long)0);
}
}
cout << ans << endl;
return 0;
}
E - A += v
运行时间限制: 2 秒 / 内存限制: 1024 MiB
分数 : 475 分
问题描述
给定整数 N、M 以及长度为 N 的整数列 A=(A₁, A₂, …, A_N),其中各元素均在 1 到 M 之间。
对于该整数列 A,执行以下操作 10¹⁰⁰ 次。
从 1 到 M 的整数中,找出在 A 中出现次数最少的整数设为 v。但是,如果存在多个这样的 v,则取值最小的那个。然后,将 v 添加到 A 的末尾。
给定 Q 个查询。在第 i 个查询中,给出整数 X_i,请求在执行上述操作 10¹⁰⁰ 次之后,求 A_{X_i} 的值。
制约
1 ≤ N, M ≤ 5×10⁵
1 ≤ A_i ≤ M
1 ≤ Q ≤ 2×10⁵
1 ≤ X_i ≤ 10¹⁸
输入的所有值均为整数
输入
输入以以下格式从标准输入给出。
N M
A_1 A_2 … A_N
Q
X_1
X_2
⋮
X_Q
输出
请按行输出Q行。
第i行,请输出第i个查询的答案。
样例输入1
3 3
1 1 2
8
1
2
3
4
5
6
7
8
样例输入1
1
1
2
3
2
3
1
2
起初 A=(1,1,2)。在每次操作中,A 会如下变化。
- 第一次:A 中 1、2、3 的个数分别为 2、1、0,因此取 v=3。将 v 添加到 A 的末尾,得到 A=(1,1,2,3)。
- 第二次:A 中 1、2、3 的个数分别为 2、1、1,因此取 v=2。将 v 添加到 A 的末尾,得到 A=(1,1,2,3,2)。
- 第三次:A 中 1、2、3 的个数分别为 2、2、1,因此取 v=3。将 v 添加到 A 的末尾,得到 A=(1,1,2,3,2,3)。
⋮
经过10¹⁰⁰次操作后,A 变为 A=(1,1,2,3,2,3,1,2,…)。
样例输入2
7 30
20 26 3 14 4 4 9
10
31
9
21
23
97
99
30
79
57
3
样例输入2
30
2
18
21
7
9
29
19
27
3
solve
Code1
太懒了于是直接复制一份@lihaochen2014
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Node {
long long v;
int id;
};
int N, M, Q;
int A[500010];
Node X[200010];
int ans[200010];
int freq[500010];
int bit[500010];
vector<int> cnt[500010];
int lowbit(int x) {
return x & -x;
}
void add(int x) {
while (x <= M) {
bit[x]++;
x += lowbit(x);
}
}
long long query(int x) {
long long res = 0;
while (x > 0) {
res += bit[x];
x -= lowbit(x);
}
return res;
}
int main()
{
cin >> N >> M ;
for (int i = 1; i <= N; ++i) {
cin >> A[i] ;
freq[A[i]]++;
}
cin >> Q ;
for (int i = 1; i <= Q; ++i) {
cin >> X[i].v ;
X[i].id = i;
}
sort(X + 1, X + 1 + Q, [](Node a, Node b) {
return a.v < b.v;
});
for (int i = 1; i <= M; ++i) {
cnt[freq[i]].push_back(i);
};
int j = 1;
while (j <= Q && X[j].v <= N) {
ans[X[j].id] = A[X[j].v];
j++;
}
long long marked = N;
for (int i = 0; i <= N && j <= Q; ++i) {
for (int num : cnt[i]) {
add(num);
}
long long pmk = marked;
marked += query(M);
while (j <= Q && X[j].v <= marked) {
long long k = X[j].v - pmk;
int res = -1, l = 1, r = M;
//cout << X[j].v << " " << k << '\n' ;
while (l <= r) {
int mid = (l + r) / 2;
//cout << mid << ' ' << query(mid) << '\n' ;
if (query(mid) >= k) {
res = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
//cout << res << '\n' ;
ans[X[j].id] = res;
j++;
}
//cout << '\n' ;
}
while (j <= Q) {
ans[X[j].id] = (X[j].v - marked - 1) % M + 1;
j++;
}
for (int i = 1; i <= Q; ++i) {
cout << ans[i] << '\n' ;
}
return 0;
}
Code2
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+10;
int n,m,q;
int a[maxn],b[maxn],cnt[maxn],k;
signed main()
{
cin >> n>> m;
for (int i=1;i<=n;i++)
{
cin >> a[i];
b[i]=(cnt[a[i]]++)*m+a[i];
/*出现了一次,就存本身,出现了两次,就存
m+本身,三次四次同理,可以通过输出看规律
这样在后续处理中就可以算出位置*/
}
sort(b+1,b+n+1);
// for (int i=1;i<=n;i++) cout << a[i] << " ";
// cout << endl;
for (int i=1;i<=n;i++) b[i]-=i;
/*对上述可以通过输出观察作用*/
// for (int i=1;i<=n;i++) cout << a[i] << " ";
// cout << endl;
cin >> q;
while (q--)
{
cin >> k;
if (k<=n) cout << a[k] << endl;
/*对于k<=n,仍在原序列查找即可*/
else
{/*对于k>n,由于是在后方扩展,因此在原数列查不到
其实有两种情况:已完成一组后错(t>n)和
未完成一组后错(t<=n)
已经完成的直接%m(若%完==0,直接赋m)
未完成的向后错
可以合并成以下情况*/
int t=lower_bound(b+1,b+n+1,k-n)-b-1;
int ans=(k+t-n-1)%m+1;
cout << ans << endl;
}
}
return 0;
}
F - Grid Clipping
运行时间限制: 4 秒 / 内存限制: 1024 MiB
分数 : 500 分
问题描述
有一个 H 行 W 列的网格。我们称从上数第 r 行、从左数第 c 列的方格为方格 (r,c)。每个方格都被涂成黑色或白色,对于 k=1,2,…,N,有方格 (R_k,C_k) 被涂成黑色,其余的 HW−N 个方格被涂成白色。
请求出在这个网格中,有多少个纵向 h 行、横向 w 列的矩形区域,其包含的所有方格都是白色的。
更严格地说,请求满足以下所有条件的整数对 (r_0,c_0) 的个数:
1≤r_0≤H−h+1
1≤c_0≤W−w+1
对于满足 0≤i<h, 0≤j<w 的所有整数组合 (i,j),方格 (r_0+i,c_0+j) 被涂成白色。
制约
1≤h≤H≤10^9
1≤w≤W≤10^9
0≤N≤2×10^5
1≤R_k≤H
1≤C_k≤W
(R_k1,C_k1) ≠ (R_k2,C_k2) (k1 ≠ k2)
输入的所有值都是整数
输入
输入以以下格式从标准输入给出。
H W h w N
R_1 C_1
R_2 C_2
⋮
R_N C_N
输出
请输出答案。
输入样例1
3 4 2 2 3
1 3
2 4
3 1
输出样例1
2
下图中用红色圈出的两个矩形区域满足所有条件。

输入样例2
4 4 3 2 2
2 2
3 4
输出样例2
0
输入样例3
449 449 3 14 0
输出样例3
194892
输入样例4
31 9 5 7 10
14 8
8 4
18 8
12 1
8 5
9 6
18 1
14 7
5 6
26 7
输出样例4
12
solve
翻译后
考虑满足以下所有条件的 (r_0, c_0):
1≤r_0≤H−h_1
1≤c_0≤W−w_1
存在满足 0≤i<H, 0≤j<W 的整数对 (i,j),使得格子 (r_0+i, c_0+j) 被涂成黑色
设满足这些条件的 (r_0, c_0) 的数量为 X,那么所求答案为 (H−h_1)(W−w_1)−X。以下考虑如何求出这个 X。
当存在某个被涂成黑色的格子 (R_k, C_k) 时,由它满足条件的格子为 (r_0, c_0)∈[R_k−h_1, R_k]×[C_k−w_1, C_k]。因此,只需计算这些矩形区域的并集的大小即可。
求这些矩形区域并集大小的方法有很多,这里介绍一种使用 multiset 的平面扫描方法。
每个矩形区域可以通过沿 r 轴扫描来理解:当 r=R_k−h_1 时,黑色格子出现在 [C_k−w_1, C_k],当 r=R_k+1 时消失。因此,可以按照 r 的升序,用 multiset 或 map 保持当前哪些区间有黑色格子,通过计算差分即可高速计算这些面积。
通过适当实现上述方法,可以正确解决这个问题。计算复杂度为 O(NlogN)。
显然我们不会multiset
因此我们用线段树扫描线
Code
依旧照着打@TP2010
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define lson (u<<1)
#define rson (u<<1|1)
#define mid ((l+r)>>1)
const int maxn=200005;
int H,W,h,w,n;
int b[maxn<<1],num;
int tot;
int ans;
struct node
{
int x,l,r,t;
}L[maxn<<1];
bool cmp(node nd1,node nd2){return nd1.x<nd2.x;}
int t[maxn<<4],cnt[maxn<<4];
void add(int u,int l,int r)
{
if (cnt[u]) t[u]=b[r+1]-b[l];
else t[u]=t[lson]+t[rson];
}
void update(int u,int ll,int rr,int op,int l=1,int r=num-1)
{
if (ll<=l && r<=rr)
{
cnt[u]+=op;
add(u,l,r);
return;
}
if (ll<=mid) update(lson,ll,rr,op,l,mid);
if (rr>mid) update(rson,ll,rr,op,mid+1,r);
add(u,l,r);
}
signed main()
{
cin >> H >> W >> h >> w >> n;
for (int i=1;i<=n;i++)
{
int x,y;
cin >> x >> y;
int l=max((long long)1,x-h+1);
int r=min(x,H-h+1)+1;
int d=max((long long)1,y-w+1);
int u=min(y,W-w+1)+1;
b[++num]=l;
b[++num]=r;
L[++tot]={d,l,r,1};
L[++tot]={u,l,r,-1};
}
sort(b+1,b+1+num);
num=unique(b+1,b+1+num)-(b+1);
sort(L+1,L+1+tot,cmp);
for (int i=1;i<tot;i++)
{
int l=lower_bound(b+1,b+num+1,L[i].l)-b;
int r=lower_bound(b+1,b+num+1,L[i].r)-b;
int T=L[i].t;
update(1,l,r-1,T);
ans+=(L[i+1].x-L[i].x)*t[1];
}
cout << (H-h+1)*(W-w+1)-ans << endl;
return 0;
}
G - Many Repunit Sum 2
运行时间限制: 2 秒 / 内存限制: 1024 MiB
分数 : 600 分
问题描述
问题文
给定正整数 N、M。
对于正整数 d,将 d 位数的 repunit 定义为整数$∑_{i=0}^{d-1} 10^i$。
求可以表示为 N 个 1 位以上 M 位以下的 repunit(不一定不同)的和的整数个数,并对 998244353 取余。
制约
1≤N≤10^5
1≤M≤10^9
输入的所有值都是整数
输入
输入以以下格式从标准输入给出。
N M
输出
请输出答案。
输入样例1
2 3
输出样例1
6
位数在 1 位以上 3 位以下的 repunit 有 1、11、111 这三种。可以表示为这三者两数之和的整数有 2、12、22、112、122、222 这六个。
输入样例2
10 10
输出样例2
92378
输入样例3
12345 123456789
输出样例3
133394021
solve
翻译后
翻译不了一点
Code
写不了一点
侵必删

浙公网安备 33010602011771号