2024北京市赛补题

原题链接

好难...用的技巧和算法很多

K 贪心 桶

直观想 每次最小的乘二 乘二就是左移 每次把最高位最小的乘二

枚举二进制位 把所有数整到一个最高二进制位上 如果还有剩的k就同步变大 用桶维护最高二进制位 2e5*30

cpp 复制代码
vector<int>b[40];
void solve(){
	int n,k;cin>>n>>k;
  vector<int>a(n+1);
  // ,b(n+1,0);
  forr(i,1,n){
    cin>>a[i];
  }
  
  forr(i,1,n){
    int tp=a[i],cnt=0;
    while (tp)
    {
      cnt++;
      tp>>=1;
    }
    b[cnt].push_back(a[i]);
  }
  int ans=0,sm=0;
  forr(i,0,30){
    sort(b[i].begin(),b[i].end());
    if(b[i].size()==n){
      int tm=k/n;
      k%=n;
      int psm=0,ssm=0;
      forr(j,0,k-1)(psm+=b[i][j]%mod)%=mod;
      forr(j,k,b[i].size()-1)(ssm+=b[i][j]%mod)%=mod;
      (ans+=(psm*qpow(2,tm+1)%mod+ssm*qpow(2,tm)%mod)%mod)%=mod;
      break;
    }
    for(auto x:b[i]){
      if(k>0)b[i+1].push_back(x<<1),k--;
      else b[i+1].push_back(x);
    }
    if(k==0){
      forr(j,i+1,30){
        for(auto x:b[j])(ans+=x%mod)%=mod;
      }
      break;
    }
  }
  cout<<ans<<endl;
  /* 
    int ans=0,pre=0,id=n;
    forr(i,1,n-1){
      int dis=b[i+1]-b[i];
      cout<<dis<<' '<<k<<endl;
      (ans+=a[i])%=mod;
      if(dis>0){
        int sft=min(k,dis*i);
        k-=sft;
        (ans*=qpow(2,sft))%=mod;// 合并成一块了 不知道其中如何分配
      }
      if(k==0){
        id=i;
        break;
      }
    }
    
    forr(i,id,n)ans+=a[i];
    (ans*=qpow(2,k))%=mod;
    cout<<ans<<endl;  
  */
  
  
  // int ans=0,psm=0,ssm=0;
  // forr(i,1,k)(psm+=a[i])%=mod;;
  // forr(i,k+1,n)(ssm+=a[i])%=mod;
  // ans= (qpow(2,tm+1)*psm%mod+qpow(2,tm)*ssm%mod)%mod;
  // cout<<ans<<endl;
}  

D LCA找两点之间的路径 判断点是否在路径上

如果本次点在相邻两点的路径上 那么这个点不是目标经典

用LCA找两点间路径

cpp 复制代码
const int N = 2e5+10,M=1e5;
const double PI=acos(-1),eps=1e-7;
const long long mod =1e9+7, inf = 2e18 ;
int n,m,q;
int fa[N][35],dep[N];
int b[N];
vector<int>g[N];
void dfs(int now,int f){// O(nlogn)
  fa[now][0]=f;
  dep[now]=dep[f]+1;
  for(int i=1;(1<<i)<=dep[now];i++){
    fa[now][i]=fa[fa[now][i-1]][i-1];
  }

  for(auto x:g[now]){
    if(x==f)continue;
    dfs(x,now);
  }
}
int LCA(int x,int y){
  if(dep[x]<dep[y])swap(x,y);
  
  reforr(i,0,20){
    if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
  }
  if(x==y)return x;
  reforr(i,0,20){
    if(fa[x][i]!=fa[y][i]){
      x=fa[x][i],y=fa[y][i];
    }
  }
  return fa[x][0];
}
bool isanc(int x,int tar){// 确定tar是否为x的祖先
  reforr(i,0,20){
    if(dep[fa[x][i]]>=dep[tar])x=fa[x][i];// x上跳
  }

  return x==tar;
}
bool check(int p){// 判断now是不是目标景点 是1 不是0
  /*
    now是目标景点:不在相邻两点的路径上
  */
  if(p==1||p==m)return 1;// 不是两边都有点 不能确定是路过的点 那就算作目标景点
  int lp=b[p-1],rp=b[p+1],now=b[p];// 看now是否在lp rp的路上
  int f=LCA(lp,rp);

  if(dep[f]>dep[now])return 1; //now比f深度浅 now不可能在路上
  // dep[f]<=dep[now] now可能在路上
  // lp rp 通过f连成一条路 如果now在路上 now是lp或rp的一个祖先
  if(isanc(lp,now)||isanc(rp,now))return 0;
  else return 1;
}
void solve(){
  cin>>n>>m>>q;
  forr(i,1,n-1){
    int u,v;cin>>u>>v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  dfs(1,0);
  forr(i,1,m)cin>>b[i];
  int ans=0;
  forr(i,1,m)ans+=check(i);
  while (q--)
  {
    int p,w;cin>>p>>w;
    // 一个点和相邻两点状态相关
    // 消除原来的状态
    if(p-1>=1)ans-=check(p-1);
    if(p+1<=m)ans-=check(p+1);
    ans-=check(p);
    //添加新的状态
    b[p]=w;
    if(p-1>=1)ans+=check(p-1);
    if(p+1<=m)ans+=check(p+1);
    ans+=check(p);
    cout<<ans<<endl;
  }
  
}  
相关推荐
从零开始的代码生活_33 分钟前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸37 分钟前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++
TsingtaoAI1 小时前
3D高斯泼溅技术发展及其在具身智能领域的应用综述
人工智能·算法·ai·具身智能·高斯泼溅
atunet1 小时前
关于图算法中的连通分量检测与最小割问题7
算法
GIS阵地1 小时前
QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)
开发语言·前端·c++·qt·qgis
王维同学1 小时前
[原创][Windows C++]LSA 认证、安全与通知包的注册表枚举
c++·windows·安全
心运软件2 小时前
银行客户流失预测(Python 完整实战)
算法
邪神与厨二病2 小时前
牛客周赛 Round 153
python·算法
_wyt0013 小时前
完全背包问题详解
c++·背包dp
qizayaoshuap4 小时前
# ❌ 井字棋 — 鸿蒙ArkTS Minimax AI算法与博弈系统设计
人工智能·算法·华为·harmonyos