Atcoder Beginner Contest 174(ABC174) 题解

打到了 R a n k   33 Rank\ 33 ,还是不错的。

第一次顺顺畅畅没有WA地AK了一场ABC,写篇题解纪念一下……

Solution

T1

直接模拟即可。

T2

分别枚举每个点并用已给的公式算出其与原点的距离,然后统计距离不大于 k k 的点数即可。

建议用 l o n g   d o u b l e long\ double 存储。

T3

暴力即可,考虑如何快速判断 k k 1 1 时其是否能被 n n 整除。

我们可以维护一个值,即当前这么多 1 1 组成的数模 n n 的值。考虑在末尾加上一个 1 1 后,原数 x x 变为了 10 x + 1 10x+1 ,那么模数也乘 10 10 1 1 ,即模数可以 O ( 1 ) O(1) 维护

当模数为 0 0 时显然满足要求,立即输出并结束即可。注意当位数达到一定量的时候,应跳出循环输出 1 -1

T4

显然,满足要求的条件是,左边清一色的 R R 且右边清一色的 W W

于是,我们算出 W W 的数量为 c n t cnt ,在原字符串的最后 c n t cnt 位中数出不为 W W 的字符数量,即为答案。

注意,这种做法的正确性在于,在后面 c n t cnt 位中,每遇到一个不是 W W 的字符就应当与前面 n c n t n-cnt 个字符中一个不为 R R 的字符交换,此时满足要求且决策最优。

T5

首先,思考这样一个问题: 如果一个块的长度为 x x ,每次把它劈成两个块,最终要求任何一个块的长度均不超过 l e n len ,求最少劈的次数。

我们可以贪心地操作,即对于长木块,每次都劈掉一块长度为 l e n len 的,直到满足要求,此时决策最优且劈的次数为 a b 1 \lceil \frac a b \rceil -1

回到原题,可以发现是一道有单调性的二分题(最小值最大, 最大值最小这种字眼应该很敏感吧)。我们每次判断: 能否让块的最大值最终不大于 m i d mid 且劈的次数不多于 k k 次。判断的方式就是判断 i = 1 n ( a i m i d 1 ) \sum_{i=1}^n (\lceil \frac {a_i} {mid} \rceil -1) 的值是否超过了 k k ,其中前者表示,分别考虑每个块至少要被劈的次数使得其产生的新块中不含大于 m i d mid 的块。

时间复杂度为 O ( n l o g 2 n ) O(nlog_2n)

T6

莫队解法的时间复杂度为 O ( n n ) O(n \sqrt n) ,经过简单的计算,发现 50000 × 500000 3.6 × 1 0 8 50000×\sqrt {500000}≈3.6×10^8 ,以及它约为 2 2 的常数,在 2000 m s 2000ms 的时限下易被卡,所以果断放弃莫队

此时,我们可以将询问按右端点排序,维护一个序列 b b ,其中 b i b_i 表示第 i i 个位置当前对答案的贡献。显然,如果我们目前扫到了第 9 9 个位置,第 4 4 个位置与它的值一样;那么,对于之后所有右端点在 9 9 号位置及 9 9 号位置之后的询问中,第 4 4 个位置均不可能产生贡献。同时,第 9 9 个位置暂时产生了 1 1 的贡献。

于是,我们同时维护一个数组 l a s t last l a s t i last_i 记录下 i i 这个数上一次出现的位置。若目前扫到了第 i i 个位置,根据之前说的,要将第 i i 个位置的贡献值加 1 1 ;若 l a s t a i last_{a_i} (上一次出现的位置)的值不是 0 0 ,即更新过,那么 l a s t a i last_{a_i} 位置的贡献值要扣除 1 1 。一次对于 [ l , r ] [l,r] 的询问,答案显然是 i = l r b i \sum_{i=l}^r b_i ,其中 b i b_i 记录下了第 i i 个位置的贡献。

发现 b b 数组涉及到单点修改以及区间查询,可以轻松用树状数组来维护。我们另外再维护一个指针 j j ,指向马上需要解决的一个询问,如果该询问解决了就 j + + j++ ,跳到下一个询问。最后注意,我们先前已将询问按右端点进行了排序,最终输出要还原顺序

时间复杂度 O ( n l o g 2 n ) O(nlog_2n)

Code

T1

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n;

signed main()
{
	cin>>n;
	if (n>=30)  cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	
	return 0;
}

T2

#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;

int n,d,ans=0;
double x,y;

signed main()
{
	cin>>n>>d;
	for (int i=1;i<=n;i++)
	{
		cin>>x>>y;
		
		double len=sqrt(x*x+y*y);
		if (len<=d)  ans++;
	}
	cout<<ans<<endl;
	
	return 0;
}

T3

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,ii=0,now=0;

signed main()
{
	cin>>n;
	while (ii<=80000000)
	{
		ii++;
		now=(now*10+7)%n;
		
		if (now==0)  return cout<<ii<<endl,0;
	}
	cout<<-1<<endl;
	return 0;
}

T4

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,cnt=0,ans=0;
char a[200005];

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)  cin>>a[i];
	for (int i=1;i<=n;i++)
	{
		if (a[i]=='W')  cnt++;
	}
	for (int i=n-cnt+1;i<=n;i++)
	{
		if (a[i]!='W')  ans++;
	}
	cout<<ans<<endl;
	
	return 0;
}

T5

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,k,ans=1e9+7;
int a[200005];

inline int up(int aa,int bb)
{
	if (aa%bb==0)  return aa/bb;
	else return (aa/bb)+1;
}

bool check(int len)//check函数
{
	int tot=0;
	for (int i=1;i<=n;i++)  tot=tot+up(a[i],len)-1;
	
	if (tot<=k)  return true;
	else return false;
}

int Binary_search(int l,int r)//递归式二分写法
{
	if (l==r||l+1==r)
	{
		if (check(l))  ans=min(ans,l);
		if (check(r))  ans=min(ans,r);
		return ans; 
	}
	int mid=(l+r)>>1;
	if (check(mid))
	{
		ans=min(ans,mid);
		return Binary_search(l,mid);
	}
	else return Binary_search(mid+1,r);
}

signed main()
{
	cin>>n>>k;
	for (int i=1;i<=n;i++)  cin>>a[i];
	
	cout<<Binary_search(1,1e9)<<endl;
	
	return 0;
}

T6

#include <bits/stdc++.h>
using namespace std;

int n,tmp,j=1;
int a[1000005],tree[2000005],last[1000005],ans[1000005];

struct node
{
	int rt,l,r;
}q[1000005];

inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	
	while (ch<'0'||ch>'9')
	{
		if (ch=='-')  w=-w;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^'0');
		ch=getchar();
	}
	return s*w;
}

bool cmp(node x,node y)
{
	return x.r<y.r;
}

inline int lowbit(int k)
{
	return k&(-k);
}

inline void change(int rt,int num)
{
	while (rt<=n)
	{
		tree[rt]+=num;
		rt+=lowbit(rt); 
	}
}

inline int query(int r)
{
	int tot=0;
	while (r>=1)
	{
		tot+=tree[r];
		r-=lowbit(r);
	}
	return tot;
}

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)  a[i]=read();
	
	cin>>tmp;
	for (int i=1;i<=tmp;i++)  q[i].l=read(),q[i].r=read(),q[i].rt=i;
	
	sort(q+1,q+tmp+1,cmp);
	
	for (int i=1;i<=n;i++)
	{
		change(i,1);
		if (last[a[i]])  change(last[a[i]],-1);
		while (i==q[j].r&&j<=tmp)  ans[q[j].rt]=query(q[j].r)-query(q[j].l-1),j++;
		
		last[a[i]]=i;
	}
	for (int i=1;i<=tmp;i++)  cout<<ans[i]<<endl;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/107752303