2025 北京市大学生程序设计竞赛暨“小米杯”全国邀请赛

E 计算几何 坐标系转换 二分答案

题意:在一条线上找一个点到所给点的最大距离最短

最大的最小,考虑对最大距离进行二分答案,check(dis)判断dis能不能≥\geq≥线上某个点到每个点的距离

坐标变换后,设线上合理的某个点是(xc,0)(x_c,0)(xc,0),(x−xc)2+y2≤dis2(x-x_c)^2+y^2\leq dis^2(x−xc)2+y2≤dis2,xcx_cxc的范围是[xc−y2−dis2,xc+y2−dis2][x_c-\sqrt{y^2-dis^2},x_c+\sqrt{y^2-dis^2}][xc−y2−dis2 ,xc+y2−dis2 ],交集不是空集即合理

cpp 复制代码
const double PI=acos(-1);
const long long mod =998244353, inf = 1e9 ;
double a,b,c;
// double dis(pdd p){
//   return abs(a*p.xx+b*p.yy+c)/sqrt(a*a+b*b);
// }

void solve(){
    int n;cin>>n;
    vector<pdd>pos(n+1);
    forr(i,1,n)cin>>pos[i].xx>>pos[i].yy;
    cin>>a>>b>>c;
    double mag=sqrt(a*a+b*b);
    double theta=acos(abs(b/mag));
    if(-a*b<0)theta=-theta;
    // cout<<theta<<endl;
    //转换坐标系
    forr(i,1,n){
      double nx=pos[i].xx*cos(theta)+pos[i].yy*sin(theta);
      double ny=pos[i].yy*cos(theta)-pos[i].xx*sin(theta)+(b==0?-c/a:c*cos(theta)/b);
      // double ny=pos[i].yy*cos(theta)-pos[i].xx*sin(theta);

      pos[i].xx=nx,pos[i].yy=ny;
      // cout<<nx<<' '<<ny<<endl;
    }
    
    // 二分答案 枚举最后的距离答案
    auto check=[&](double dis)->bool{
      double lmx=-1e18,rmn=1e18;
      forr(i,1,n){
        if(dis-abs(pos[i].yy)<-1e-8)return false;
        double d=sqrt(dis*dis-pos[i].yy*pos[i].yy);
        lmx=max(lmx,pos[i].xx-d),rmn=min(rmn,pos[i].xx+d);
        if(rmn-lmx<-1e-8)return false;
      }
      return true;
    };

    double l=0,r=1e7;
    while (r-l>1e-8)
    {
      double mid=(l+r)/2;
      if(check(mid)){
        r=mid;
      }else l=mid;
    }
    // cout<<"ans";
    cout<<fixed<<setprecision(8)<<r<<endl;
}

G dp

一看这个题就感觉是dp,本次选哪一个之前的路径会影响到未来,但是受限于水平不会实现...

动态规划成立的前提:一旦当前阶段的状态确定,未来的演变与过去无关,当前状态已包含所有对未来决策有用的信息

每次更新的是以当前萤火虫作为末尾的状态每次从上一个记录的w的质因数p和颜色cw的质因数p和颜色cw的质因数p和颜色c转移过来 dp[p][c]dp[p][c]dp[p][c]

但是和本次颜色不同的颜色有很多,一一判断会超时

为了让最后答案链最长,需要关注前面最长的链,但是最长链的末尾颜色和本次颜色相同的话这个链就断了,末尾颜色与最长链不同的次长链也会是最优解的一个选择,本次更新后不是选之前的最长链就是次长链

设计color[p][0最长/1次长],dp[p][0最长/1次长]color[p][0最长/1次长],dp[p][0最长/1次长]color[p][0最长/1次长],dp[p][0最长/1次长],或者直接合二为一dp[p][0最长/1次长][0记录的颜色/1链的长度]]dp[p][0最长/1次长][0记录的颜色/1链的长度]]dp[p][0最长/1次长][0记录的颜色/1链的长度]]

cpp 复制代码
const int N = 5e5,M=1e9+1;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e9 ;
vector<int>prime;
int minp[N+10];// 每个数的最小质因数
void find_p(){
    minp[1]=1;
    forr(i,2,N){
        if(!minp[i]){
            minp[i]=i;
            prime.push_back(i);
        }
        for(auto p:prime){
            if(i*p>=N)break;
            minp[i*p]=p;
            if(p==minp[i])break;
            
        }
    }
}
array<array<int,2>,2> f[N+10];
void solve(){
    find_p();
    int n;cin>>n;
    
    vector<int>w(n+1),c(n+1);
    forr(i,1,n)cin>>w[i];
    forr(i,1,n)cin>>c[i];
    f[1][0][0]=c[1],f[1][0][1]=1;
    f[1][1][0]=c[1],f[1][1][1]=1;
    forr(i,1,n){
    	//分解质因数
        vector<int>factor;
        while(w[i]>1){
            int x=minp[w[i]];
            while (w[i]%x==0)w[i]/=x;
            factor.push_back(x);
        }
		// 找本次最优
        int res=1;
        for(auto p:factor){
            if(c[i]!=f[p][0][0])res=max(res,f[p][0][1]+1);
            if(c[i]!=f[p][1][0])res=max(res,f[p][1][1]+1);
        }
        //记录最优值
        for(auto p:factor){
          /*
          这里正解代码写的是
           if (c[i] != f[x][0][0]) {
                if (res > f[x][0][1]) {
                    f[x][1] = f[x][0];
                    f[x][0] = {c[i], res};
                } else if (res > f[x][1][1]) {
                    f[x][1] = {c[i], res};
                }
            } else {
                if (res > f[x][0][1]) {
                    f[x][0] = {c[i], res};
                }
            }
            assert(f[x][0][0] != f[x][1][0]);
          */
          /*
          之前的错误解法
          if(res>f[p][0][1]){
                f[p][1]={c[i],res};
                f[p][0]={c[i],res};//最大次大都成一个颜色了
            }else if(res>f[p][1][1]){
                f[p][1]={c[i],res};
            }
            会wa在:
            7
					2 5 4 3 6 3 5 
					6 9 7 7 7 2 8 
          */
            
          //需要保证最大次大的颜色不同
          if(c[i]!=f[p][0][0]){//颜色不同
            if(res>f[p][0][1]){//放到最大的位置
              f[p][1]=f[p][0];
              f[p][0]={c[i],res};
            }else if(res>f[p][1][1]){//放到次大的位置
              f[p][1]={c[i],res};
            }
          }else{//颜色相同
            if(res>f[p][0][1]){
              f[p][0][1]=res;//直接刷新
            }
          }
        }
        
        
    }
    int ans=1;
    for(auto p:prime){
        ans=max(ans,f[p][0][1]);
    }
    cout<<ans<<endl;

}
相关推荐
蜡笔小马9 分钟前
09.C++设计模式-外观模式
c++·设计模式·外观模式
2301_8008951011 分钟前
蓝桥杯第十二届b组国赛真题--备战国赛版h
算法·蓝桥杯
晚会者荣14 分钟前
C++11_3:包装器,智能指针
c++
员宇宙14 分钟前
k8s学习笔记
笔记·学习·kubernetes
手写码匠15 分钟前
手写 AI Prompt Injection 防护系统:从零实现 LLM 安全边界
人工智能·深度学习·算法·aigc
薇茗17 分钟前
【初阶数据结构】 升沉有序的平仄 排序
c语言·数据结构·算法·排序算法
handler0118 分钟前
TCP(传输控制协议)核心机制与底层原理
linux·网络·c++·笔记·网络协议·tcp/ip·操作系统
王老师青少年编程18 分钟前
csp信奥赛C++高频考点专项训练之字符串 --【字符串综合】:遍历问题
c++·字符串·csp·高频考点·信奥赛
yoyo_zzm21 分钟前
五大编程语言对比:PHP、C、C++、C#、易语言
c语言·c++·php
杰之行24 分钟前
Fast-DDS Transport 层架构详解
c++·人工智能