牛客周賽Round 67 個人題解(A~F)

Persona_owl發表於2024-11-11

牛客周賽Round 67 個人題解(A~F)

牛客周賽 Round 67

A-排序危機

題目分析

  • 相對位置不會改變,用三個·字串模擬即可
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
void solve(){
	int n;cin>>n;
	string s;cin>>s;
	s=" "+s;
	string s1,s2,s3;
	for(int i=1;i<=n;i++){
		if(s[i]>='a' && s[i]<='z') s1+=s[i];
		if(s[i]>='0' && s[i]<='9') s2+=s[i];
		if(s[i]>='A' && s[i]<='Z') s3+=s[i];
	}
	cout<<s1<<s2<<s3<<endl;
}
int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

B-小歪商店故事:卷

題目分析

  • 式子變化一下a<b*c/d,注意處理一下整數和小數的區別
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int ans[N];
void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		int a,b,c,d;cin>>a>>b>>c>>d;
		int t=(b*c)/d;
		if(t*d<b*c) ans[i]=a-t;
		else ans[i]=a-t+1;
  	 }
	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

C-小苯的計算式_牛客周賽 Round 67

題目分析

  • 暴力,因為A+B=C,len(A)+len(B)+len(C)+2=n,列舉A即可算B,然後判斷滿不滿足題目條件即可
  • 一個小trick,計算一個數字的位數可以用log10(x)+1快速求出
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
void solve(){
	int n,c;cin>>n>>c;
	int len=log10(c)+1;
	n=n-len-2;
	int ans=0;
	for(int a=0;a<=c;a++){
		int b=c-a;
		int lena=a?log10(a)+1:1;
		int lenb=b?log10(b)+1:1;
		if(lena+lenb!=n) continue;
		ans++;
	}
	cout<<ans<<endl;
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

D-K_牛客周賽 Round 67

題目分析

  • 構造題目,首先容易發現當k的最大值只能為n,即所有數都相同,所以當k>n時無解
  • 考慮構造k<n,可以用交替的01串構造,如k=5,n=8,只需01010111
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=2e5+10;
int a[N];
void solve(){
	int n,k;cin>>n>>k;
	if(k>n){
		cout<<"NO"<<endl;
		return;
	}
	cout<<"YES"<<endl;
	if(k==n){
		for(int i=1;i<=n;i++) cout<<0<<" ";
		cout<<endl;
		return;
	}
	for(int i=1;i<=k+1;i++){
		if(i&1) a[i]=0;
		else a[i]=1;
	}
	for(int i=k+2;i<=n;i++) a[i]=a[i-1];
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	cout<<endl;
}
int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

E-小苯的區間選數_牛客周賽 Round 67

題目分析

  • 首先題目可以轉化為求[l,r]區間取一個數的最大數位和,一道很經典的問題
  • 考慮性質,將l和r每一位都分解開,若兩數數字個數相同,則有當a[i]<b[i]時,若對於b來說i之後的位置不全為9,則可以讓b[i]-1.後面全都取9,這樣一定能滿足該數屬於[l,r]且數位和不劣於原數(思考一下,因為這一位-1,後面的所有數不全為9的話一定能補上這個減掉的1)
  • 知道這個性質後就可以列舉數位了,為了防止特判,我們可以將兩數數字個數不同轉化成相同情況,即給l賦值00000
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
void solve(){
	int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;
	int l=l1+l2,r=r1+r2;
	string sl=to_string(l);
	string sr=to_string(r);
	int lenl=sl.size(),lenr=sr.size();
	int ans=0,res=0;
	if(lenl!=lenr){
		sl.assign(lenr,'0');
	} 
	for(int i=0;i<lenr;i++){
		if(sl[i]<sr[i]){
			int tmp=(lenr-i-1)*9+(sr[i]-'0'-1)+res;
			ans=max(ans,tmp);
		}
		res+=sr[i]-'0';
	}
	ans=max(ans,res);
	cout<<ans<<endl;
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}

F-小Z的樹遷移_牛客周賽 Round 67

解題思路

  • 樹上k-son問題,這裡給出dfs序的做法
  • 其實我們需要維護的是對於點u如何快速找到指定層數的點,並求出最大的權值和,首先目標點的層數應該為dep[u]+d
  • 考慮怎麼維護子樹資訊,這裡運用到dfs序的方法,我們記錄訪問一個點的時間為st[i],離開的時間為ed[i],容易發現一個性質,若v在u的子樹中那麼一定有st[u]<=st[v]<=ed[v]<=ed[u],那麼我們可以去預處理每一個點的dfs序,接下來對每一層的點存下對應點的dfs序並排序
  • 然後對於給定點u,我們找到需要到的對應層數,我們要找這一層上在u子樹中的點,怎麼做呢?我們可以對這一層記錄的點的dfs序二分,二分邊界即為上一點的條件,這樣既可以log時間內找到區間
  • 找到區間之後,我們要做的就是在這個區間內選一個點,使得點u到該點的權值和最大,假設選擇的點為v,u的父親為fa,則權值和為sum[v]-sum[fa],由於u是固定點,所以等價於我們在該區間內選擇一個點x,使得sum[x]最大,典型的RMQ問題,這裡可以用st錶快速維護
  • 具體細節可以看程式碼的實現
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
struct node{
	int to,w;
};
vector<node> g[N];
int st[N],ed[N],dep[N],sum[N],f[N][20];
int p[N],cnt[N],t[N];//cnt存每一層點個數的字首和
int n,tot=0;
bool cmp(int x,int y){
	if(dep[x]==dep[y]) return st[x]<st[y];
	return dep[x]<dep[y];
}
//求dfs序,並維護sum與dep陣列
void dfs(int u,int fa){
	st[u]=++tot;
	for(auto [v,w]:g[u]){
		if(v==fa) continue;
		dep[v]=dep[u]+1;
		sum[v]=sum[u]+w;
		dfs(v,u);
	}
	ed[u]=tot;
}
void init(){
	for(int j=1;j<19;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            f[i][j]=max(f[i][j-1], f[i+(1<<(j-1))][j-1]);
        }
    }
}
int query(int l,int r){
	int k=log2(r-l+1);
	return max(f[l][k],f[r-(1<<k)+1][k]);
}
void test(){
	for(int i=1;i<=n;i++) cout<<p[i]<<" ";
	cout<<endl;
	for(int i=1;i<=n;i++) cout<<cnt[i]<<" ";
	cout<<endl;
	for(int i=1;i<=n;i++) cout<<st[i]<<" ";
	cout<<endl;
	for(int i=1;i<=n;i++) cout<<t[i]<<" ";
	cout<<endl;
}
void solve(){
	cin>>n;
	for(int i=1;i<=n-1;i++){
		int u,v,w;cin>>u>>v>>w;
		g[u].push_back({v,w});
		g[v].push_back({u,w});
	}
	dfs(1,0);
	for(int i=1;i<=n;i++) p[i]=i;
	sort(p+1,p+n+1,cmp);
	
	for(int i=1;i<=n;i++){
		int t=dep[p[i]];
		cnt[t]=i;
		f[i][0]=sum[p[i]];
	}
	init();
	for(int i=1;i<=n;i++) t[i]=st[p[i]];
//	test();	
	int q;cin>>q;
	while(q--){
		int u,d;cin>>u>>d;
		int tmp=dep[u]+d;
		int l=lower_bound(t+cnt[tmp-1]+1,t+cnt[tmp]+1,st[u])-t;
        int r=upper_bound(t+cnt[tmp-1]+1,t+cnt[tmp]+1,ed[u])-t;
        if(!cnt[tmp] || r<=l){
        	cout<<-1<<endl;
        }
        else{
        	int ans=query(l,r-1)-sum[u];
        	cout<<ans<<endl;
        }
	}
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int T=1;
	while(T--) solve();
	return 0;
}

相關文章