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_i=f_i+(f_{i+1+(i!=n-1)}+1)\times p\times E \]

  • 扣一点血:

\[f_i=f_i+(f_{i+1}+1)\times(1-p\times E) \]

最后输出 \(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;
}
posted @ 2022-12-03 23:04  Binary_Lee  阅读(50)  评论(0编辑  收藏  举报
Title