25CCPC东北邀请赛vp补题

感觉还好 签到不难

F 枚举 暴力

枚举范围内每一个合法时间(最多6012=720个),难在计算角度
时针分针分别算, d e g h = 30 ∗ ( h + m 60 ) = 30 h + m 2 deg_h=30*(h+\frac{m}{60})=30h+\frac{m}{2} degh=30∗(h+60m)=30h+2m,有/2,可以把所有角度
2避免使用double

cpp 复制代码
int deg(int x,int y,int x0,int y0){
    int h=2*30*x+2*30*y/60,h0=2*30*x0+2*30*y0/60;
    int m=2*360*y/60,m0=2*360*y0/60;
    // double res=(6*min({fabs(y-y0),60-fabs(y-y0)})+30*min({fabs(h-h0),12-fabs(h-h0)}));
    int res=min(abs(h-h0),720-abs(h-h0))+min(abs(m-m0),720-abs(m-m0));
    return res;
}
void solve(){
    int x,y,x0,y0,x1,y1;cin>>x>>y>>x0>>y0>>x1>>y1;
    int ans=inf;
    int ax,ay;
    if(x0==x1){
        forr(j,y0,y1){
            int d=deg(x,y,x0,j);
            if(d<ans)ax=x0,ay=j,ans=d;
        }
    }else{
        forr(i,x0,x1){
            forr(j,(i==x0?y0:0),(i==x1?y1:59)){
                int d=deg(x,y,i,j);
                // cout<<i<<' '<<j<<' '<<d<<endl;
                if(d<ans)ax=i,ay=j,ans=d;
            }
        }
    }
    cout<<ax<<' '<<ay<<endl;
    
}

H 二分 配对

参考@Hongs_Cai 的题解

以下分析来自千问:

为什么直接把所有城市的"容纳能力"加起来得 s u m c a p a c i t y sum_{capacity} sumcapacity,只要 ≥ s u m b \geq sum_b ≥sumb就有解?

这是一个非常深刻的结论,基于本题的特殊结构:每组人只有一个城市不能去

  • 在这个特定的约束下,局部的容量限制之和如果大于等于总人数,那么一定存在一种分配方案。(因为 b i b_i bi可以散开分到不同城市)
  • 这其实隐含了霍尔婚嫁定理的结论。因为每组人只被一个城市拒绝,这种"排斥关系"非常稀疏。

霍尔婚嫁定理:来自@汪湜

通俗说法:任意k个人,他们总共能选择的对象集合大小必须至少是k,才能一人一个。

反例:如果有 3 个人,但他们加起来只认识 2 个对象,那么这 3 个人不可能每个人都匹配成功(必然有人落单)。这就是违反了霍尔条件。
对这个题来说,每组人只有一个城市不能去, s u m b sum_b sumb个人的能选择对象集合大小就是所有城市容纳能力的和 s u m c a p a c i t y sum_{capacity} sumcapacity,只要 s u m c a p a c i t y ≥ s u m b sum_{capacity}\geq sum_b sumcapacity≥sumb就有合理分配方式

注:如果每组人可以避开多个城市,这个贪心求和就不成立了,必须用网络流。但本题每组只避开一个,使得问题退化为简单的求和判断。

cpp 复制代码
void solve(){
  int n;cin>>n;
  int sb=0;
  vector<int>a(n+1),b(n+1),c(n+1);
  forr(i,1,n)cin>>a[i];
  forr(i,1,n){
    cin>>b[i];
    sb+=b[i];
  }
  forr(i,1,n)cin>>c[i];
  vector<int>mxb(n+1,sb);//根据相冲规则 每个城市预期最大的接纳人数
  forr(i,1,n){
    mxb[a[i]]-=b[i];//犯冲的不不接纳
  }

  auto check=[&](int x)->bool{
    vector<int>d(n+1);
    forr(i,1,n)d[i]=(x/c[i]); // 根据x的最大容量
    int s_cap=0; // 总的最大容量
    forr(i,1,n){
      s_cap+=min(d[i],mxb[i]);
    }
    if(s_cap<sb)return false; //小了
    else return true; // 大了
  };
  int l=0,r=inf;
  while (l<r)
  {
    int mid=(l+r)>>1;
    if(check(mid))r=mid;
    else l=mid+1;
  }
  cout<<r<<endl;
  
}

/*
 2
 2
 1 2
 3 4
 1 2
 5
 1 2 3 4 5
 5 4 3 2 1
 2 1 4 3 5
*/

L 大模拟

之后有空补...

相关推荐
plus4s2 小时前
3月20日(进阶11)
c++·算法
jyyyx的算法博客2 小时前
【跳跃游戏】题集
算法
2301_816651222 小时前
移动语义在容器中的应用
开发语言·c++·算法
不要秃头的小孩2 小时前
力扣刷题——77. 组合
数据结构·python·算法·leetcode
2401_857918292 小时前
实时数据处理中的C++应用
开发语言·c++·算法
2401_884563242 小时前
C++中的装饰器模式实战
开发语言·c++·算法
MicroTech20252 小时前
微算法科技(NASDAQ :MLGO)抗量子区块链技术:筑牢量子时代的数字安全防线
科技·算法·区块链
.select.2 小时前
C++ 单例模式
java·c++·单例模式
Ivanqhz2 小时前
图着色寄存器分配算法(Graph Coloring)
开发语言·javascript·python·算法·蓝桥杯·rust