河南萌新联赛2024第(四)场:河南理工大学

        B-小雷的神奇电脑_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:最大同或对。01字典数模板。

int n,ans=0;
int arr[100005];
int ch[2000006][2];  开到1e6RE一个点
int idx=0;
void insert(int x){
    int p=0;
    for(int i=32;i>=0;i--){         ai在int范围内,所以i得是32.
        int j=(x>>i)&1;
        if(!ch[p][j]) ch[p][j]=++idx;
        p=ch[p][j];
    }
}
int query(int x){
    int p=0,res=0;
    for(int i=32;i>=0;i--){        ai在int范围内,所以i得是32.
        int j=(x>>i)&1;
        if(j&&ch[p][0]){
            res+=(1ll<<i);
            p=ch[p][0];
        }
        else if(!j&&ch[p][1]){
            res+=(1ll<<i);
            p=ch[p][1];
        }
        else p=ch[p][j];
    }
    return res;
}
在1e5个数字中选两个,进行异或运算,求可得到的最大异或值---01字典树
P10471 最大异或对The XOR Largest Pair
https://www.luogu.com.cn/problem/P10471
void solve(){                 补B
    cin>>n;
    for(int i=1;i<=n;i++) cin>>arr[i],insert(arr[i]);
    for(int i=1;i<=n;i++) ans=max(ans,query(arr[i]));
    cout<<ans;
}

C-岗位分配_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:

隔板法--太神奇了..
多余的m-n个人,分配到n个岗位中
因为可以有志愿者空闲下来,那么可以再加一个岗位安放空闲的志愿者。
那么在放好必要的志愿者之后,多余的志愿者可以随意放到n+1个岗位上.
例如样例:
即x1+x2+x3+x4=4  (x>=0)
隔板法要求x>=1,那么可以变形为,(x1+1)+(x2+1)+(x3+1)+(x4+1)=8   这样(x'>=1)
那么按照隔板法,方案数为comb(m-1,n),即在m-1个空位中,放n个板子,得到n+1个不同的岗位安排.
const int mod=998244353;
int n,m;
int quickpow(int a,int b){
    int res=1;
    while(b){
        if(b&1) res*=a,res%=mod;
        a*=a,a%=mod;
        b>>=1;
    }
    return res;
}
comb模板
int fac[2003],inv[2003];
void init(int x){
    fac[0]=1;
    for(int i=1;i<=x;i++) fac[i]=fac[i-1]*i%mod;
    inv[x]=quickpow(fac[x],mod-2);      预处理逆元
    for(int i=x-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
int comb(int x,int y){  x个中选y个
    if(y>x) return 0;
    if(y==0) return 1;
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
隔板法--太神奇了..
多余的m-n个人,分配到n个岗位中
因为可以有志愿者空闲下来,那么可以再加一个岗位安放空闲的志愿者。
那么在放好必要的志愿者之后,多余的志愿者可以随意放到n+1个岗位上.
例如样例:
即x1+x2+x3+x4=4  (x>=0)
隔板法要求x>=1,那么可以变形为,(x1+1)+(x2+1)+(x3+1)+(x4+1)=8   这样(x'>=1)
那么按照隔板法,方案数为comb(m-1,n),即在m-1个空位中,放n个板子,得到n+1个不同的岗位安排.
岗位分配
https://ac.nowcoder.com/acm/contest/88269/C
void solve(){
    cin>>n>>m;
    init(2000);
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        m-=x;
    }
    m+=n+1;
    cout<<comb(m-1,n);
}

dp做法:

dp[i][j]定义为,在满足基本条件的前提,考虑前i个岗位,放置j个志愿者的方案数.定义在优化成前缀和后有所不同.
const int mod=998244353;
int n,m;
int dp[2][2003];   dp[i][j]定义为,在满足基本条件的前提,考虑前i个岗位,放置j个志愿者的方案数.优化成前缀和后有所不同
最暴力的是三重循环的,还要枚举前一个放置了几个.这一个循环可以用前缀和给优化了.
岗位分配
https://ac.nowcoder.com/acm/contest/88269/C
void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        m-=x;
    }
    dp[0][0]=1;
    int ans=0;
    for(int i=1;i<=n;i++){
        int idx=i&1;
        for(int j=0;j<=m;j++){
            dp[idx][j]=dp[idx][j-1]+dp[idx^1][j],dp[idx][j]%=mod;这里优化成前缀和,并且优化为滚动数组
//            for(int k=0;k<=j;k++){   k=[0,j],这一层优化成前缀和
//                dp[i][j]+=dp[i-1][j-k],dp[i][j]%=mod;
//            }
            if(i==n) ans+=dp[idx][j],ans%=mod;   的确是这样的.
        }
    }
    cout<<ans;
}

K-比赛_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:枚举裁判,用树状数组维护左边(大于/小于)等于当前裁判的个数,和右边(大于/小于)等于当前裁判的个数。要注意的是,左右边和裁判相等的值是算重了一次的,所以要减去一次左右和裁判相等的值的个数的乘积。

树状数组--单点修改,区间查询(作差)
#define lowbit(x) (x)&-(x)
int n,mx,ans=0;
int arr[20004];
int cL[100005],cR[100005];
void update(int x,int k,int typ){   0左1右
    for(int i=x;i<=mx;i+=lowbit(i)){
        typ?cR[i]+=k:cL[i]+=k;
    }
}
int query(int x,int typ){
    int res=0;
    for(int i=x;i;i-=lowbit(i)){
        typ?res+=cR[i]:res+=cL[i];
    }
    return res;
}
比赛
https://ac.nowcoder.com/acm/contest/88269/K
void solve(){      great    key:枚举中间的裁判,计算左右满足条件的个数
    cin>>n;
    mx=0,ans=0;         警钟长鸣:多组样例,清空!!
    for(int i=1;i<=n;i++) cin>>arr[i],mx=max(mx,arr[i]);
    update(arr[1],1,0);           单点修改
    for(int i=3;i<=n;i++) update(arr[i],1,1);
    for(int i=2;i<=n-1;i++){
        ans+=query(arr[i],0)*(query(mx,1)-query(arr[i]-1,1));    左小右大
        ans+=(query(mx,0)-query(arr[i]-1,0))*query(arr[i],1);    左大右小
        ans-=(query(arr[i],0)-query(arr[i]-1,0))*(query(arr[i],1)-query(arr[i]-1,1)); 查询单点值              减去和arr[i]相等的,算重的
        update(arr[i],1,0);
        if(i+1<=n-1) update(arr[i+1],-1,1);
    }
    cout<<ans<<endl;
    for(int i=1;i<=mx;i++) cL[i]=0,cR[i]=0;    警钟长鸣:多组样例,清空!!
}

E-AND_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:欧拉筛。容易发现最小的合法区间为[2,3,5],这样只要计算<=y的质数个数,就可以o(1)知道有多少个合法区间.

const int maxn=1e8;
int x,y;
int pri[6000006],idx=0;     前1e8个数字有不到6e6个质数
//vector<int> pri;   动态,静态都行.静态不能开1e8,多余了.
bool mark[maxn+10];   MLE--不要开int mark[]!!之前一直都是开bool的,不知道为什么这次写了int,而且还是long long的
//unordered_map<int,bool> mark;     TLE
void getpri(){
    for(int i=2;i<=maxn;i++){
        if(!mark[i]) pri[++idx]=i;
        for(int j=1;j<=idx;j++){
            if(i*pri[j]>maxn) break;
            mark[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}
前1e8个数字有不到6e6个质数,怎么找区间?--都不用找,很rz.
don't give up too early.
再思考一会,会发现2这个数字是必要的,因为只有2能提供第0位那个0,其他的质数都是奇数,第0位全是1
并且最小的合法区间为[2,3,5],这样只要计算<=y的质数个数,就可以o(1)知道有多少个合法区间.
AND
https://ac.nowcoder.com/acm/contest/88269/E
void solve(){
    cin>>x>>y;
    int l=1,r=idx,cnt1=0,cnt2=0;
    while(l<=r){                    压行
        int mid=(l+r)>>1;
        pri[mid]<=y?cnt1=mid,l=mid+1:r=mid-1;
    }
    cnt2=0,l=1,r=idx;
    while(l<=r){
        int mid=(l+r)>>1;
        pri[mid]<=x-1?cnt2=mid,l=mid+1:r=mid-1;
    }
    x==2?cout<<cnt1<<" "<<max(0ll,cnt1-2)<<endl:cout<<cnt1-cnt2<<" "<<0<<endl;
}

I-马拉松_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:dfs,跑出x的合法孩子和y的合法孩子。

int n,x,y;
vector<int> vct[300005];
int dfs(int s,int fa,int typ){
    if(s==y&&typ==0) return 0;
    if(s==x&&typ==1) return 0;
    int res=1;
    for(auto v:vct[s]){
        if(v!=fa) {
            int cur=dfs(v,s,typ);
            if(cur==0&&s!=x&&typ==0) return 0;
            if(cur==0&&s!=y&&typ==1) return 0;
            else res+=cur;
        }
    }
    return res;
}
/马拉松
/https://ac.nowcoder.com/acm/contest/88269/I
void solve(){           I    dfs
    cin>>n>>x>>y;
    for(int i=1;i<=n-1;i++){
        int u,v; cin>>u>>v;
        vct[u].emplace_back(v);
        vct[v].emplace_back(u);
    }
    cout<<dfs(x,0,0)*dfs(y,0,1);
}

J-尖塔第四强的高手_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)

思路:lca模板。

int n,r,q;
vector<int> vct[100005];
int F[30],idx=3;    idx取值为[1,24]
void init(){
    F[1]=1,F[2]=2;
    while(1){
        F[idx]=F[idx-1]+F[idx-2];
        if(F[idx]>=100000) break;
        idx++;
    }
}
int dep[100005],fa[100005][20];   跳17步足矣
void dfs(int s,int father){
    dep[s]=dep[father]+1;
    fa[s][0]=father;
    for(int i=1;i<=17;i++) fa[s][i]=fa[fa[s][i-1]][i-1];
    for(auto v:vct[s]) if(v!=father) dfs(v,s);
}
int lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=17;i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    if(u==v) return u;
    for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
尖塔第四强的高手
https://ac.nowcoder.com/acm/contest/88269/J
void solve(){           J    手搓lca
    cin>>n>>r>>q;
    init();
    for(int i=1;i<=n-1;i++){
        int u,v; cin>>u>>v;
        vct[u].emplace_back(v);
        vct[v].emplace_back(u);
    }
    dfs(r,0);
    while(q--){
        int x,k; cin>>x>>k;
        vector<int> test;
        for(int i=k;i<=24;i++){
            int num=F[i]+x;
            if(num>n) break;
            test.emplace_back(num);
        }
        if(test.size()==0) cout<<"0"<<endl;
        else{
            int cur=test[0];
            for(int i=1;i<test.size();i++) cur=lca(cur,test[i]);
            cout<<cur<<endl;
        }
    }
}

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值