打到了 ,还是不错的。
第一次顺顺畅畅没有WA地AK了一场ABC,写篇题解纪念一下……
Solution
T1
直接模拟即可。
T2
分别枚举每个点并用已给的公式算出其与原点的距离,然后统计距离不大于 的点数即可。
建议用 存储。
T3
暴力即可,考虑如何快速判断 个 时其是否能被 整除。
我们可以维护一个值,即当前这么多 组成的数模 的值。考虑在末尾加上一个 后,原数 变为了 ,那么模数也乘 加 ,即模数可以 维护。
当模数为 时显然满足要求,立即输出并结束即可。注意当位数达到一定量的时候,应跳出循环输出 。
T4
显然,满足要求的条件是,左边清一色的 且右边清一色的 。
于是,我们算出 的数量为 ,在原字符串的最后 位中数出不为 的字符数量,即为答案。
注意,这种做法的正确性在于,在后面 位中,每遇到一个不是 的字符就应当与前面 个字符中一个不为 的字符交换,此时满足要求且决策最优。
T5
首先,思考这样一个问题: 如果一个块的长度为 ,每次把它劈成两个块,最终要求任何一个块的长度均不超过 ,求最少劈的次数。
我们可以贪心地操作,即对于长木块,每次都劈掉一块长度为 的,直到满足要求,此时决策最优且劈的次数为 。
回到原题,可以发现是一道有单调性的二分题(最小值最大, 最大值最小这种字眼应该很敏感吧)。我们每次判断: 能否让块的最大值最终不大于 且劈的次数不多于 次。判断的方式就是判断 的值是否超过了 ,其中前者表示,分别考虑每个块至少要被劈的次数使得其产生的新块中不含大于 的块。
时间复杂度为 。
T6
莫队解法的时间复杂度为 ,经过简单的计算,发现 ,以及它约为 的常数,在 的时限下易被卡,所以果断放弃莫队。
此时,我们可以将询问按右端点排序,维护一个序列 ,其中 表示第 个位置当前对答案的贡献。显然,如果我们目前扫到了第 个位置,第 个位置与它的值一样;那么,对于之后所有右端点在 号位置及 号位置之后的询问中,第 个位置均不可能产生贡献。同时,第 个位置暂时产生了 的贡献。
于是,我们同时维护一个数组 , 记录下 这个数上一次出现的位置。若目前扫到了第 个位置,根据之前说的,要将第 个位置的贡献值加 ;若 (上一次出现的位置)的值不是 ,即更新过,那么 位置的贡献值要扣除 。一次对于 的询问,答案显然是 ,其中 记录下了第 个位置的贡献。
发现 数组涉及到单点修改以及区间查询,可以轻松用树状数组来维护。我们另外再维护一个指针 ,指向马上需要解决的一个询问,如果该询问解决了就 ,跳到下一个询问。最后注意,我们先前已将询问按右端点进行了排序,最终输出要还原顺序。
时间复杂度 。
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;
}