牛客周賽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;
}