[题解]AtCoder Beginner Contest 400(ABC400) A~E
A - ABC400 Party
如果\(A\)整除\(400\)就输出\(\frac{400}{A}\),否则输出-1。
时间复杂度\(O(1)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
signed main(){
cin>>n;
if(400%n==0) cout<<400/n;
else cout<<-1;
return 0;
}
B - Sum of Geometric Series
模拟即可,中途累加超过\(10^9\)就直接输出并结束。
时间复杂度\(O(\min(m,\log_n V))\),其中\(V=10^9\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k=1,ans;
signed main(){
cin>>n>>m;
m++;
while(m--){
ans+=k;
k*=n;
if(ans>1e9) break;
}
if(ans>1e9) cout<<"inf";
else cout<<ans;
return 0;
}
C - 2^a b^2
容易发现满足条件的数要么是偶完全平方数,要么是\(2\)倍的完全平方数。
因此答案就是下面两项累加:
- 偶完全平方数的数量:\(\frac{\lfloor\sqrt{n}\rfloor}{2}\)。
- \(2\)倍的完全平方数的数量:\(\lfloor\sqrt{\frac{n}{2}}\rfloor\)。
时间复杂度\(O(\log n)\)。
注意直接使用<cmath>中的sqrt()会产生误差导致WA,需要手写(才知道sqrt()的误差这么大)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int sq(int x){
int l=0,r=1e9;
while(l<r){
int mid=(l+r+1)>>1;
if(mid*mid>x) r=mid-1;
else l=mid;
}
return l;
}
signed main(){
cin>>n;
int a=sq(n),b=sq(n/2);
cout<<a/2+b<<"\n";
return 0;
}
D - Takahashi the Wall Breaker
考虑转成图论问题求解。
将每个位置\((x,y)\)看做节点,向其上下左右\(1\sim 2\)步处,共\(8\)个位置\((x',y')\)分别建边。
如果\((x,y)\)到\((x',y')\)中途(不包括\((x,y)\))没有经过墙壁,那么边权就是\(0\),否则边权就是\(1\)。
最后,从起点到终点的最短路即为答案。
由于边权只有\(0\)和\(1\),我们可以使用0-1 BFS来求解单源最短路。
时间复杂度\(O(V+E)=O(nm)\),其中\(V,E\)分别表示点数和边数。
点击查看代码
#include<bits/stdc++.h>
#define H 1010
#define N 1000010
#define M 16000010
using namespace std;
int n,m,sx,sy,tx,ty,idx,head[N],d[N];
struct edge{int nxt,to;bool w;}e[M];
deque<int> q;
bitset<N> vis;
int dx[8]{-2,-1,0,0,0,0,1,2};
int dy[8]{0,0,-2,-1,1,2,0,0};
string s[H];
int conv(int x,int y){return x*m+y+1;}
void add(int u,int v,bool w){
e[++idx]={head[u],v,w};
head[u]=idx;
}
void tadd(int x,int y,int xx,int yy){
if(xx<0||yy<0||xx>=n||yy>=m) return;
bool w=0;
if(abs(xx-x)+abs(yy-y)==2) w|=(s[(xx+x)/2][(yy+y)/2]=='#');
w|=(s[xx][yy]=='#');
add(conv(x,y),conv(xx,yy),w);
}
void bfs(int s){
d[s]=0,q.push_back(s);
while(!q.empty()){
int t=q.front();
q.pop_front();
if(vis[t]) continue;
vis[t]=1;
for(int i=head[t],v;i;i=e[i].nxt){
v=e[i].to;
if(d[t]+e[i].w>=d[v]) continue;
d[v]=d[t]+e[i].w;
if(e[i].w) q.push_back(v);
else q.push_front(v);
}
}
}
signed main(){
memset(d,0x3f,sizeof d);
cin>>n>>m;
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) for(int d=0;d<8;d++) tadd(i,j,i+dx[d],j+dy[d]);
cin>>sx>>sy>>tx>>ty;
bfs(conv(sx-1,sy-1));
cout<<d[conv(tx-1,ty-1)]<<"\n";
return 0;
}
赛时稍微想麻烦了,其实并不需要像我这样真的建图,仅需在BFS中现用现遍历即可。
E - Ringo's Favorite Numbers 3
由于每个质因数的次数都是偶数,所以满足条件的数\(a\)一定是平方数。
那么我们不妨直接枚举\(\sqrt{a}\),它需要满足:
- \(\sqrt{a}\)恰有\(2\)个不同的质因数。
考虑怎么快速计算出\(O(\sqrt{a})=O(\sqrt{V})\approx 10^6\) 以内满足上述条件的数。
我们可以先筛出此范围内的素数,然后直接暴力枚举就好,并不会超时。
这是因为只要我们枚举的过程没有冗余遍历,那么根据质因数分解定理,枚举出的数一定不会重复,时间复杂度就是\(O(\sqrt{V})\)。
我们可以用一个桶来记录枚举出的数,每次询问就找桶中的前一个枚举出的数,输出其平方即可。可以使用前缀和+二分在\(O(\log \sqrt{V})\)内解决。
总时间复杂度\(O(Q\log V+\sqrt{V})\),其中\(\log V\)是二分求平方根的复杂度。
这道题直接调用sqrt()不会WA,不过数大的时候(比如C题)还是建议手写。
点击查看代码
``cpp
include<bits/stdc++.h>
define int long long
define N 1000010
using namespace std;
int pri[N],idx,flg[N],q,a;
bitset
void init(int n){//线性筛
for(int i=2;i<=n;i++){
if(!npri[i]) pri[++idx]=i;
for(int j=1;j<=idx;j++){
if(ipri[j]>n) break;
npri[ipri[j]]=1;
if(i%pri[j]==0) break;
}
}
}
int sq(int x){//开平方
int l=0,r=1e9;
while(l<r){
int mid=(l+r+1)>>1;
if(midmid>x) r=mid-1;
else l=mid;
}
return l;
}
signed main(){
init(1e6);
for(int i=1;i<idx;i++)
for(int j=i+1;pri[j]pri[i]<=1e6;j++)
for(int k=pri[i]pri[j];k<=1e6;k=pri[i])
for(int l=k;l<=1e6;l=pri[j])
flg[l]=1;
for(int i=1;i<=1e6;i++) flg[i]+=flg[i-1];
cin>>q;
while(q--){
cin>>a;
a=sq(a);
a=lower_bound(flg+1,flg+1000001,flg[a])-flg;
cout<<aa<<"\n";
}
return 0;
}
</details>
浙公网安备 33010602011771号