ABC 174 题解
Atcoder Beginner Contest 174
A
给一个 N,如果 N≥30,输出 "Yes",否则输出 "No"。
#include<bits/stdc++.h>
using namespace std;
int main(){
int x;
cin>>x;
if(x>=30)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
B
输入,N,D。并给出 N 个坐标。求有多少个坐标与 (0,0) 的距离小于 D。
根据坐标公式,只需要满足 x∗x+y∗y≤D∗D 即可
#include<bits/stdc++.h>
using namespace std;
long long n,d;
int main(){
cin>>n>>d;
long long x,y;
int ans=0;
for(int i=1;i<=n;i++){
cin>>x>>y;
if(x*x+y*y<=d*d){
ans++;
}
}
cout<<ans;
return 0;
}
C
给一个 N,7777...(i 个 7) 是 N 的倍数的最小 i。
这道题因为数据较小,可以用暴力的解法做。
从 1 到 n 枚举 7 的个数。又因为 ((i%j)10+7)%j=(i10+7)%j
所以我们可以对其余数进行判断,即余数等于 0 时,可以取到。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int res=7%n;
if(res==n||res==0){
cout<<1;
return 0;
}
for(int i=2;i<=1000000;i++){
res=(res*10+7)%n;
if(res==n||res==0){
cout<<i;
return 0;
}
}
cout<<-1;
return 0;
}
D
给一个长度为 N 的仅有'W'和'R'的字符串,每一次操作可以将一个 W 改为 R 或把 R 改为 W 或调换两个字符的位置。
请问最少多少次操作后,没有 W 在 R 左边。
由题意得只需保证左边全是 R,右边全是 W 即可。
我们贪心可以发现,更改操作是可以被调换替换掉的,并且每一次将最左边的 R 换最右边的 W 即可。
#include<bits/stdc++.h>
using namespace std;
long long n;
char c[200005];
int w[200005];
int main(){
cin>>n;
int sum=0;
memset(w,0x3f3f3f3f,sizeof(w));
for(int i=1;i<=n;i++){
cin>>c[i];
if(c[i]=='W')w[++sum]=i;//记录下每一个W的位置,以便之后调换位置
}
int ans=0;
int point=1;
for(int i=n;i>=1;i--){
if(c[i]=='R'&&i>w[point]){
swap(c[i],c[w[point]]);
point++;
ans++;
}
}
cout<<ans<<endl;
return 0;
}
E
给 N 个木条,每一个木条长度位 a[i],每一次操作可以将一个木条随意切成两段,问 m 次操作之后,这些木条中最长的那块的长度最小是多少。
一道裸的二分答案,只需要二分木条的长度即可。有点类似 luogu 上的《小木条》。
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[200005];
bool isok(int mid){
int sum=0;
for(int i=1;i<=n;i++){
sum+=(a[i]-1)/mid+1-1;
}
// cout<<"mid"<<mid<<" sum:"<<sum<<endl;
if(sum>k)return false;
return true;
}
int main(){
cin>>n>>k;
int maxn=0;
for(int i=1;i<=n;i++){
cin>>a[i];
maxn=max(a[i],maxn);
}
int l=1,r=maxn+1;
int ans;
while(l<r){
int mid=(l+r)>>1;
if(isok(mid)){
r=mid;
ans=mid;
}else{
l=mid+1;
}
}
cout<<ans<<endl;
return 0;
}
F
给 N 个数,M 次询问。每次询问输入 l,r,输出 l-r 中的不同数字的种数。
本题是一道主席树,由于记录的是种数,所以是不满足直接区间加的。
于是就考虑其他的操作:
我们用 was 记录下当前节点上一个节点的位置,当且仅当 was[i]<=l 的时候,加入答案。
当当前点的值并不是当前区间的第一个,会重复记录同一个数,不符合题意,故每次记录第一个出现的数字即可。
我们用主席树维护这个 was 数组即可。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int Maxn=3e7;
int a[500005],li[500005];
int was[500005];
int last[500005];
struct t{
int ls,rs,sum;
}tree[Maxn];
int root[500005];
int tot=0;
int build(int l,int r){
int now=++tot;
if(l==r)return now;
int mid=(l+r)/2;
tree[now].ls=build(l,mid);
tree[now].rs=build(mid+1,r);
return now;
}
int modify(int now,int l,int r,int goal,int sum){
int pos=++tot;
tree[pos]=tree[now];
if(l==r){
tree[pos].sum+=sum;
return pos;
}
int mid=(l+r)>>1;
if(goal<=mid){
tree[pos].ls=modify(tree[now].ls,l,mid,goal,sum);
}
else if(goal>mid){
tree[pos].rs=modify(tree[now].rs,mid+1,r,goal,sum);
}
tree[pos].sum=tree[tree[pos].ls].sum+tree[tree[pos].rs].sum;
return pos;
}
int anss=0;
void query(int pos1,int pos2,int gl,int gr,int l,int r){
if(gl<=l&&r<=gr){
anss=anss+tree[pos2].sum-tree[pos1].sum;
return ;
}
int mid=(l+r)>>1;
if(mid>=gl){
query(tree[pos1].ls,tree[pos2].ls,gl,gr,l,mid);
}
if(mid<gr)query(tree[pos1].rs,tree[pos2].rs,gl,gr,mid+1,r);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
was[i]=last[a[i]];
last[a[i]]=i;
}
root[0]=build(0,n);
for(int i=1;i<=n;i++){
root[i]=modify(root[i-1],0,n,was[i],1);
}
int l,r;
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
anss=0;
query(root[l-1],root[r],0,l-1,0,n);
cout<<anss<<endl;
}
return 0;
}
感受到 hry 写题解的艰辛让我们给hry爱的抱抱以表感谢~(这是一个梗)