AtCoder Beginner Contest 330 ABCDE
A - Counting Passes
签到题,不多说。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n,m; cin>>n>>m;
int cnt = 0;
for(int i = 1;i <= n; i++)
{
int x; cin>>x;
cnt += (x >= m);
}
cout<<cnt<<"\n";
return 0;
}
B - Minimize Abs 1
题意:有一个长为 \(N\) 的数列 \(A\) 和两个整数 \(L,R\)。对于每个 \(A_{i}\),你需要选出一个数 \(X_{i}\),满足如下条件:
- \(L\le X_{i}\le R\)
- 对于所有整数 \(L\le Y\le R\),\(|X_{i}-A_{i}|\le|Y-A_i|\)
思路:二分
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n,l,r; cin>>n>>l>>r;
for(int i = 1;i <= n; i++)
{
int x; cin>>x;
int L = l,R = r;
while(L<=R)
{
int mid = (L+R)/2;
if(mid >= x) R = mid-1;
else L = mid+1;
}
cout<<min(r,R+1)<<" ";
}
return 0;
}
C - Minimize Abs 2
题意:给你一个整数\(D\),找到对于非负整数\(x,y\)的\(|x^2+y^2-D|\)的最小值
思路:相比上一题,这是2个数,怎么办哩。可以考虑枚举x,二分y。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
ll n; cin>>n;
ll ans = 1e18;
for(ll i = 1;i*i <= n; i++)
{
ll x = i;
ll l = 0,r = 1e6;
while(l<=r)
{
ll mid = (l+r)>>1;
if(mid*mid+x*x >= n)r = mid-1;
else l = mid+1;
}
//cout<<"x = "<<x<<" r+1 = "<<r+1<<"\n";
ans = min({ans,min(abs(x*x+r*r-n),abs(x*x+(r+1)*(r+1)-n))});
}
cout<<ans<<"\n";
return 0;
}
D - Counting Ls
题意:现有一个 \(N\) 行 \(N\) 列的字符数组,满足对于每个 \(1 \le i \le N,1 \le j \le N\) 都有 $ S_{i,j} \in {o,x} $
请问在该数组里有多少个满足以下条件的三方格组:
-
三个格子内都是 \(o\)
-
三个方格互不相同
-
恰好有两个方格在同一行
-
恰好有两个方格在同一列
思路:藕一开始的思路是,可以先用前缀和求出每个点朝四个方向的贡献,然后加起来。
下面是藕写的依托答辩QAQ...
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
char a[2010][2010];
int b[2010][2010],b1[2010][2010],b2[2010][2010],b3[2010][2010];
int c[2010][2010],c1[2010][2010],c2[2010][2010],c3[2010][2010];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n; cin>>n;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
cin>>a[i][j];
for(int i = 1;i <= n; i++)
{
for(int j = n;j >= 1; j--)
{
b[i][j] = b[i][j+1]+(a[i][j]=='o');
}
}
for(int j = 1;j <= n; j++)
{
for(int i = n;i >= 1; i--)
{
c[i][j] = c[i+1][j]+(a[i][j]=='o');
}
}
for(int i = n;i >= 1; i--)
{
for(int j = 1;j <= n; j++)
{
b1[i][j] = b1[i][j-1]+(a[i][j]=='o');
}
}
for(int j = n;j >= 1; j--)
{
for(int i = 1;i <= n; i++)
{
c1[i][j] = c1[i-1][j]+(a[i][j]=='o');
}
}
for(int i = n;i >= 1; i--)
{
for(int j = n;j >= 1; j--)
{
b2[i][j] = b2[i][j+1]+(a[i][j]=='o');
}
}
for(int j = 1;j <= n ; j++)
{
for(int i = 1;i <= n; i++)
{
c2[i][j] = c2[i-1][j]+(a[i][j]=='o');
}
}
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= n; j++)
{
b3[i][j] = b3[i][j-1]+(a[i][j]=='o');
}
}
for(int j = n;j >= 1 ; j--)
{
for(int i = n;i >= 1; i--)
{
c3[i][j] = c3[i+1][j]+(a[i][j]=='o');
}
}
// for(int i = 1;i <= n; i++)
// {
// for(int j = 1;j <= n; j++)
// cout<<b[i][j]<<" ";
// cout<<"\n";
// }
ll ans = 0;
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= n; j++)
{
if(a[i][j]=='o'){
ans += (b[i][j]-1)*(c[i][j]-1);
ans += (b1[i][j]-1)*(c1[i][j]-1);
ans += (b2[i][j]-1)*(c2[i][j]-1);
ans += (b3[i][j]-1)*(c3[i][j]-1);
}
}
}
cout<<ans<<"\n";
return 0;
}
但是想想其实没有那么复杂,因为不用考虑方向呀,直接统计行列的贡献即可。
// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
char a[2010][2010];
int r[2010],c[2010];
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
int n; cin>>n;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)
cin>>a[i][j];
for(int i = 1;i <= n; i++)
{
for(int j = 1;j <= n; j++)
{
if(a[i][j]=='o')
r[i]++,c[j]++;
}
}
ll ans = 0;
for(int i = 1;i <= n; i++)
for(int j = 1;j <= n; j++)if(a[i][j]=='o'){
ans += (r[i]-1)*(c[j]-1);
}
cout<<ans<<"\n";
return 0;
}
E - Mex and Update
题意:给定一个序列,支持单点修改,每次修改后输出全局 \(\operatorname{mex}\)。
一个序列的 \(\operatorname{mex}\) 定义为,序列中最小的没有出现过的非负整数。
思路:权值树状数组+二分,具体看代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 201000;
template<class T>
struct BIT {
T c[N];
int size;
void resize(int s) { size = s;}
T query(int x) { // 1 ... x
assert(x <= size);
T s = 0;
for (; x; x -= x & (-x)) {
s += c[x];
}
return s;
}
void modify(int x, T s) { // a[x] += s
assert(x != 0);
for (; x <= size; x += x & (-x)) {
c[x] += s;
}
}
};
BIT<ll> tr;
int n,q,a[N],vis[N];
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>q;
tr.resize(n+1);
for(int i = 1;i <= n; i++)
{
cin>>a[i];
a[i]++;//树状数组1 base的
a[i] = min(a[i],n+1);//虽然a[i]范围很大,但是mex的值只会在n+1以内。
vis[a[i]]++;
if(vis[a[i]]==1)tr.modify(a[i],1);//存在改为1
}
while(q--)
{
int i,x; cin>>i>>x;
x = min(x,n+1);
x++;
vis[a[i]]--;
if(vis[a[i]]==0)tr.modify(a[i],-1);
a[i] = x;
vis[a[i]]++;
if(vis[a[i]]==1)tr.modify(a[i],1);
int l = 1,r = n+1;
while(l<=r)
{
int mid = (l+r)/2;
if(tr.query(mid) == mid) l = mid+1;
else r = mid-1;
}
cout<<l-1<<"\n";
}
return 0;
}