牛客OI周赛14-普及组全部题解

eg:好久不见的普及组题目,自信满满以为自己ak了,结果C题莫名被卡常(后来开了氧气优化就过了,我一直以为氧气优化评测机会自己开不用手动开),D题公式精度问题被卡,最后rk14,btw牛客一场上绿还是很高兴的嘿嘿嘿。牛客OI周赛14-普及组全部题解_第1张图片
传送门

A

题意:统计一个字符串里有多少个不同的字符。
题解:map或者set随便搞。

#include
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
char s[maxn];
map<char,int>mp; 
int main(){
	scanf("%s",&s);
	int len=strlen(s);
	for(int i=0;i<len;i++)mp[s[i]] ++;
	printf("%d\n",mp.size());
	return 0;
}

B

题意:类似于统计水仙花数,一组1e6范围。
题解:读入一个判断一个即可。

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,ans;
ll quick(ll a,int b){
	ll res=1;
	while(b){
		if(b&1)res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
bool check(ll x){
	ll res=0,t=0,xx=x;
	while(xx){
		t++;
		xx/=10;
	}
	xx=x;
	while(x){
		ll k=x%10;
		res+=quick(k,t);
		x/=10;
	}
	if(res==xx)return true;
	return false;
}
int main(){
	scanf("%d",&n); 
	for(int i=1;i<=n;i++){
		ll x;
		scanf("%lld",&x);
		if(check(x))ans++;
	}
	printf("%d\n",ans);
	return 0;
}

C

题意:给出一颗无根树,让你确定他的根,使得深度之和最小。
题解:没看懂官方题解,我的做法是找到树的重心,然后跑一遍dfs即可。复杂度应该是O(2n),可能vector被卡常了?,以后还是记得开氧气优化。

#pragma GCC optimize(2)
#include
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,ans,size=INF;
vector<int>G[maxn];
int son[maxn],vis[maxn];
void dfs(int cur){
	vis[cur]=1;
	son[cur]=0;
	int tmp=0;
	for(int i=0;i<G[cur].size();i++){
		int u=G[cur][i];
		if(!vis[u]){
			dfs(u);
			son[cur]+=son[u]+1;
			tmp=max(tmp,son[u]+1); 
		}
	}
	tmp=max(tmp,n-son[cur]-1);
	if(tmp<size || tmp==size && cur<ans){
		ans=cur;
		size=tmp;
	}
}
ll sum=0;
void dfs2(int x,int fa,int dep){
	for(int i=0;i<G[x].size();i++){
		int u=G[x][i];
		if(u==fa)continue;
		dfs2(u,x,dep+1);
	}
	sum=sum+1ll*dep;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1); 
	dfs2(ans,-1,0);
	printf("%lld\n",sum);
	return 0;
}

D

题意:对于每个点i有pi的概率往右走,问走完n个点的期望是多少。
题解:概率dp的题目。设 d i d_i di为在当前第i个任务到结束还有多久,那么对于第i个点它有 p i p_i pi的概率跳到后面一天还有 1 − p i 1-p_i 1pi的概率回到前面一天,所以对应的方程就为 − ( 1 − p i ) d i − 1 + d i − p i d i + 1 = 1 -(1-p_i)d_{i-1}+d_i-p_id_{i+1}=1 (1pi)di1+dipidi+1=1,那么列出所有的方程组,高斯消元即可解决,btw如果直接用高斯消元会有精度问题最后只能85,但如果我们直接拿On扫一遍的话就可以过了。。

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n;
double a[maxn],f[maxn][5],d[maxn];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf",&a[i]);
	for(int i=1;i<=n;i++)
		d[i+1]=(d[i]-1+(a[i]-1)*d[i-1])/a[i];
	printf("%.3lf\n",-d[n+1]);
	return 0;
}

你可能感兴趣的:(ACM)