AtCoder Beginner Contest 280 题解
A - Pawn on a Grid
看样例猜题意(
要求的是 #
的数量,直接判断。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
int n,m,ans;
char c;
signed main(){
IOS;TIE;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c;
if(c=='#') ans++;
}
}
cout<<ans<<endl;
return 0;
}
B - Inverse Prefix Sum
看样例猜题意*2
直接输出差分数组就好了。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
int n,a[200005];
signed main(){
IOS;TIE;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cout<<a[i]-a[i-1]<<' ';
cout<<endl;
return 0;
}
C - Extra Character
两个字符串第一个不同位置加一个一定是合法的。正确性显然。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
string s,t;
signed main(){
IOS;TIE;
cin>>s>>t;
for(int i=0;i<t.size();i++){
if(s[i]!=t[i]){
cout<<i+1<<endl;
return 0;
}
}
return 0;
}
D - Factorial and Multiple
一开始傻掉萎了两发(
直接二分答案就好,二分答案为 \(x\) 的阶乘。
如何判断 \(x\) 是否合法?设 \(cnt_{p_i}\) 为原来的 \(k\) 所含质因数 \(p_i\) 的数量,显然需要 \(1\sim x\) 中所有数分解质因数后每一个 \(p_i\) 的数量之和都 \(>cnt_{p_i}\)。
考虑如何快速计算 \(1\sim x\) 中各质因数数量之和。设要求的质因数为 \(p_i\),则 \(1\sim x\) 中质因数 含一个及以上 \(p_i\) 的数的数量为 \(\lfloor\frac x {p_i}\rfloor\),含两个及以上 \(p_i\) 的数的数量为 \(\lfloor\frac x {{p_i}^2}\rfloor\),含三个及以上 \(p_i\) 的数的数量为 \(\lfloor\frac x {{p_i}^3}\rfloor\),以此类推。
然后就做完了。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
int k,n;
map<int,int> mp,mp2;
bool check(int mid){
for(auto i:mp){
int cnt=0,tmp=i.fi;
while(tmp<=mid) cnt+=mid/tmp,tmp*=i.fi;
if(cnt<i.se) return 0;
}
return 1;
}
signed main(){
IOS;TIE;
cin>>k;
int l=1,r=k,ans;
for(int i=2;i*i<=k;i++){
while(k%i==0) mp[i]++,k/=i;
}
if(k>1) mp[k]++;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}
E - Critical Hit
最基础的概率 \(\text{DP}\)。考虑记 \(f_i\) 表示使怪物血量降低至 \(i\) 的期望攻击次数。同时因为给出的 \(p\) 不是实际概率,实际概率为 \(p\div 100\),每次写逆元比较麻烦,所以事先算好 \(E=100^{mod-2}\),这样 \(\div 100\) 时只要 \(\times E\) 即可。
初始 \(f_n=0\),然后倒序枚举。每个值的贡献由扣两点血和扣一点血组成:
- 扣两点血( i=n-1 时只能照扣一点算):
- 扣一点血:
最后输出 \(f_0\) 即可。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
#define mod 998244353
using namespace std;
int n,p,f[200005];
int ksm(int x,int b){
int ans=1;
while(b){
if(b&1) ans=ans*x%mod;
x=x*x%mod;
b>>=1;
}
return ans;
}
signed main(){
IOS;TIE;
cin>>n>>p;
int E=ksm(100,mod-2);
f[n]=0;
for(int i=n-1;i>=0;i--){
f[i]+=(f[i+1+(i!=n-1)]+1)*p%mod*E%mod,f[i]%=mod;
f[i]+=(f[i+1]+1)*(1-p*E%mod)%mod,f[i]%=mod;
f[i]+=mod,f[i]%=mod;
}
cout<<f[0]<<endl;
return 0;
}
F - Pay or Receive
智慧题。赛时贺了个带权并查集,后来发现直接 \(\text{DFS}\) 似乎更简单?
大题思路差不多。
首先是 nan
的情况,只需判断两点是否在同一连通块中即可。
然后是 inf
的情况。不难发现路径要无限长只能是出现了 \(>0\) 的环,这样的话环所在的整个连通块中,任意两点之间都是 inf
。考虑如何判断这样的正环。首先按题意建图,然后在每个连通块内跑一遍 \(\text{DFS}\) 搞出一颗生成树并记下到每个点的距离。若没有正环,则初始连边的距离是和生成树跑出来的距离相等的。换句话说,两点间怎么走距离都是相等的。然后只要给出现距离矛盾的点所在的连通块都打上标记即可。
剩下的直接用生成树跑出来的距离算。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
#define mod 998244353
using namespace std;
int n,m,q,u,v,w,col[100005],cnt,f[100005];
bool mark[100005],vis[100005];
struct node{
int to,dis;
};
vector<node> a[100005];
void dfs(int x,int c){
col[x]=c,vis[x]=1;
for(int i=0;i<a[x].size();i++){
node tmp=a[x][i];
if(!vis[tmp.to]){
f[tmp.to]=f[x]+tmp.dis;
dfs(tmp.to,c);
}
}
}
signed main(){
IOS;TIE;
cin>>n>>m>>q;
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
a[u].push_back({v,w}),a[v].push_back({u,-w});
}
for(int i=1;i<=n;i++){
if(!vis[i]) dfs(i,++cnt);
}
for(int i=1;i<=n;i++){
for(int j=0;j<a[i].size();j++){
node tmp=a[i][j];
if(f[tmp.to]!=f[i]+tmp.dis) mark[col[i]]=1;
}
}
while(q--){
cin>>u>>v;
if(col[u]!=col[v]) cout<<"nan"<<endl;
else if(mark[col[u]]) cout<<"inf"<<endl;
else cout<<f[v]-f[u]<<endl;
}
return 0;
}
也附上带权并查集的代码:
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
#define mod 998244353
using namespace std;
int n,m,q,u,v,w,fa[200005],f[200005];
bool mark[200005];
int find(int x){
if(x==fa[x]) return x;
int tmp=fa[x];
fa[x]=find(fa[x]);
f[x]+=f[tmp];
return fa[x];
}
void merge(int x,int y,int fx,int fy,int k){
fa[fx]=fy;
f[fx]=f[y]+k-f[x];
mark[fy]|=mark[fx];
}
signed main(){
IOS;TIE;
cin>>n>>m>>q;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++){
cin>>u>>v>>w;
int fx=find(u),fy=find(v);
if(fx^fy) merge(u,v,fx,fy,w);
else if(f[u]^(f[v]+w)) mark[fx]=1;
}
while(q--){
cin>>u>>v;
int fx=find(u),fy=find(v);
if(fx^fy) cout<<"nan"<<endl;
else if(mark[fx]) cout<<"inf"<<endl;
else cout<<f[u]-f[v]<<endl;
}
return 0;
}