AtCoder Beginner Contest 174
A - Air Conditioner
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
if(t>=30) cout<<"Yes\n";
else cout<<"No\n";
return 0;
}
B - Distance
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,d;
cin>>n>>d;
int ans=0;
for(int i=1;i<=n;i++){
double x,y;
cin>>x>>y;
if(sqrt(x*x+y*y)<=(double)d) ans++;
}
cout<<ans<<"\n";
return 0;
}
C - Repsept*
吐槽这个题,不应该放在C
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
LL k;cin>>k;
LL x=7%k,ans=1;
while(1){
if(!x) break;
if(ans>1000000) break;
x=x*10+7;
x%=k;
ans++;
}
if(!x) cout<<ans<<"\n";
else cout<<"-1\n";
return 0;
}
D - Alter Altar (思维)
这个D也挺水的,显然符合要求的目标状态就是R都集中在左边,W都集中在右边,那么直接数一下左边有多少W需要与右边R交换就好了。
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
string s;
cin>>s;
int r = 0;
for(int i=0;i<n;i++)
if(s[i]=='R') r++; //目标状态左侧R的数目
int ans = 0;
for(int i=0;i<r;i++)
if(s[i]=='W') ans++; //原串中左侧有多少W需要与右侧R交换
cout<<ans<<"\n";
return 0;
}
E - Logs (二分答案)
这个二分答案一眼就看出来了,其实也挺水,就和切木棒的二分几乎都一样了。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+7;
int a[N];
int n,k,t;
bool check(int mid)
{
int ans=0;
for(int i=1;i<=n;i++){
if(a[i] > mid) ans += a[i]/mid; //看看达到此时的最大值需要的最少切割次数
if(ans>k) return 0;
}
return 1;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i],t=max(t,a[i]);
int l=1,r=t;
while(l<=r){
int mid = l+r>>1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout<<r+1;
return 0;
}
F - Range Set Query (离线化+树状数组)
洛谷原题 QAQ,abc是没人管了吗。P1972
当然做法很多,好像主席树也可 QWQ
思路:对于
[
1
,
r
]
[1,r]
[1,r] 内不同颜色的球的个数,我们有一种思路去解决,我们开一个数组vis,比如在第x个位置出现了3这个颜色,那么我们就只把x位置置为1,之前3出现的位置都归为0,那么在vis中求
[
1
,
r
]
[1,r]
[1,r] 的前缀和
s
u
m
(
1
,
r
)
sum(1,r)
sum(1,r) 即是此区间的颜色种类数。
然后我们考虑能不能利用上这个前缀和,由于我们都只保留的每种颜色的最后一个位置,那么在此区间内只有满足需要求的区间的右端点为 r 的前缀和的差值才是正确的,比如
s
u
m
(
1
,
r
)
−
s
u
m
(
1
,
l
−
1
)
sum(1,r)-sum(1,l-1)
sum(1,r)−sum(1,l−1) 是
[
l
,
r
]
[l,r]
[l,r] 区间内不同颜色的个数,但是
s
u
m
(
1
,
j
)
−
s
u
m
(
1
,
i
−
1
)
,
i
≤
j
<
r
sum(1,j)-sum(1,i-1),i \le j< r
sum(1,j)−sum(1,i−1),i≤j<r 就不是
[
i
,
j
]
[i,j]
[i,j] 的不同颜色个数。
所以我们就直接离线处理询问,把每次询问的区间按右端点从小到大排序,然后在遍历按上述处理即可。
由于要单点修改并求前缀和,所以就是树状数组比较方便了。
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+7;
struct Node{
int l,r;
int i;
}q[N];
int tr[N];
int n,m;
int a[N],vis[N];
int ans[N];
int lowbit(int x){
return x&-x;
}
void add(int x,int v){
for(int i = x;i<=n;i+=lowbit(i))
tr[i] += v;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=tr[i];
return ans;
}
bool cmp(Node a,Node b){
return a.r<b.r;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].i = i;
}
sort(q+1,q+m+1,cmp);
int j = 1;
for(int i=1;i<=m;i++){ //每次求右边界为r的区间
while(j <= q[i].r){
if(vis[a[j]]) add(vis[a[j]],-1);
add(j,1);
vis[a[j]] = j;
j++;
}
ans[q[i].i] = query(q[i].r) - query(q[i].l-1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]); //按询问次序输出
return 0;
}