ABC330 A-E 题解

ABC330题解

AtCoder Beginner Contest 330

A - Counting Passes

思路:

枚举一遍,当前数大于L使ans+1即可.

代码:

#include<iostream>
#define int long long
using namespace std;
int n, l, ans;
int x;
signed main()
{
cin >> n >> l;
for(int i=1; i<=n; i++)
{
cin >> x;
if(x >= l)
{
ans ++;
}
}
cout << ans;
return 0;
}

B - Minimize Abs 1

思路:

枚举一遍,当前数在L,R之间,结果就是它本身,小于LL,大于RR.

代码:

#include<iostream>
#define int long long
using namespace std;
int n, l, r;
int x;
signed main()
{
cin >> n >> l >> r;
for(int i=1; i<=n; i++)
{
cin >> x;
if(x <= l)
{
cout << l << " ";
continue;
}
if(x >= r)
{
cout << r << " ";
continue;
}
cout << x << " ";
}
return 0;
}

C - Minimize Abs 2

思路:

枚举i:0d为第一个数,以1为左边界,di2+1为右边界,判定条件为mid2di2之间的大小关系,每次更新边界后ans=minans,|di2mid2|为条件二分查找第二个数.

其中di2为当前的i下剩余d的大小,mid为当前的第二个数(mid>i)

特判:当mid2=di2时直接输出0.

代码:

#include<iostream>
#include<cmath>
#define int long long
using namespace std;
int abss(int x)
{
return x > -x ? x : -x;
}
int d, ans = 1e18;
int t, l, r, mid;
signed main()
{
cin >> d;
for(int i=0; i*i<d; i++)
{
t = d - i*i;
l = 1;
r = sqrt(t) + 1;
while(l <= r)
{
mid = (l + r) >> 1;
if(mid * mid < t)
{
l = mid + 1;
}
else if(mid * mid > t)
{
r = mid - 1;
}
else
{
cout << 0;
return 0;
}
ans = min(ans, abss(t - mid * mid));
}
}
cout << ans;
return 0;
}

D - Counting Ls

思路:

由于元组的无序性,仅顺序不同的元组会被视为同一个元组,所以我们只统计每个o能和后面的o组成合法元组的个数.

只统计第2、3点在第1点右方、下方的方案,忽略左方、上方的点

设:
rowi表示第io的个数
coli表示第io的个数
bi,j表示第i行中第j列后每个o所在列在第i行往下o的个数总和
ci,j表示第i行中第j列后o的个数总和

则第i行第j列的o可组成的方案个数为:

  1. 当第二个点位于第j列上,第三个点位于第i行上时:
    第二个点的方案数×第三个点的方案数

    (col[j] - 1) * c[i][j+1]

  2. 当第二个点位于i,j2,第三个点位于第j2列上时:
    每个第二个点所对应的第三个点的方案数总和

    b[i][j+1]

将它们加起来,最后输出即可

代码:

#include<iostream>
#define int long long
using namespace std;
int n, ans;
bool a[2010][2010];
int row[2010], col[2010];
int b[2010][2010]; //第i行第j列每列的o后缀和
int c[2010][2010]; //第i行第j列的o后缀和
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
char ch;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin >> ch;
a[i][j] = (ch == 'o');
row[i] += a[i][j];
}
}
for(int j=1; j<=n; j++)
{
for(int i=1; i<=n; i++)
{
col[j] += a[i][j];
}
}
for(int i=1; i<=n; i++)
{
for(int j=n; j>=1; j--)
{
b[i][j] = b[i][j+1];
c[i][j] = c[i][j+1];
if(a[i][j])
{
b[i][j] += col[j] - 1;
c[i][j] += 1;
}
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(a[i][j])
{
ans += (col[j] - 1) * c[i][j+1];
ans += b[i][j+1];
}
}
}
cout << ans;
return 0;
}

E - Mex and Update

思路:

STL

因为A数组最多有2×105个数,所以输出的答案必定小于2×105

所以Mex可以转化为:一个存储了12×105所有数的数组,去掉A数组中的数,剩下数中的最小值

有序数组,无需插入,删除,Θ(nlogn),可以使用map,先在map里存储12×105所有数,再设cnti表示map去掉A之后剩下的每个数的数量(同样只需要存储12×105)

在输入时

  • cnt[y]--;,如果cnt[y] < 0,那么s.erase(y);
  • cnt[a[x]]++;,如果cnt[a[x]] >= 0,那么s.insert(a[x]);
  • a[x]=y;

再输出*s.begin()即可

代码:

#include<iostream>
#include<set>
#define int long long
using namespace std;
const int N = 200010;
int n, m;
int cnt[N], a[N];
set<int> s;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i=0; i<=n; i++)
{
s.insert(i);
}
for(int i=1; i<=n; i++)
{
cin >> a[i];
if(a[i] > N-10)
{
continue;
}
cnt[a[i]]--;
s.erase(a[i]);
}
while (m--)
{
int x, y;
cin >> x >> y;
if(y <= 2e5)
{
cnt[y]--;
if(cnt[y] < 0)
{
s.erase(y);
}
}
if(a[x] <= 2e5)
{
cnt[a[x]]++;
if(cnt[a[x]] >= 0)
{
s.insert(a[x]);
}
}
a[x] = y;
cout << *s.begin() << '\n';
}
return 0;
}

本文作者:gctiruct

本文链接:https://www.cnblogs.com/gctiruct/p/17858097.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   gctiruct  阅读(76)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑