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;
  }
  
}  
相关推荐
csdn_aspnet5 小时前
C语言 Lomuto分区算法(Lomuto Partition Algorithm)
c语言·开发语言·算法
谙弆悕博士5 小时前
【附C源码】从零实现C语言堆数据结构:原理、实现与应用
c语言·数据结构·算法··数据结构与算法
C+++Python7 小时前
C++ 进阶学习完整指南
java·c++·学习
sparEE8 小时前
c++值类别、右值引用和移动语义
开发语言·c++
jrrz08288 小时前
Apollo MPC Controller
c++·自动驾驶·apollo·mpc·横向控制·lateral control
gaosushexiangji9 小时前
DIC系统推荐:基于千眼狼三维数字图像相关的无人机旋翼疲劳试验全场应变与位移测量
人工智能·算法
小王C语言10 小时前
【线程概念与控制】:线程封装
jvm·c++·算法
学习,学习,在学习10 小时前
Qt工控仪器程序框架设计详解(工控多仪器控制版本)
开发语言·c++·qt
kyle~10 小时前
工程数学---点云配准卡布施(Kabsch)算法(求解最优旋转矩阵)
线性代数·算法·矩阵
张二娃同学11 小时前
03_变量常量与输入输出_printf与scanf详解
算法