2025浙江省赛补题

原题

B 枚举倍数 模拟 调和级数算时间复杂度

一开始以为有某种式子能O(1)算出来

但其实a>=2时每次改变的倍数,最多 O ( l o g n ) O(logn) O(logn)

a=1直接全按掉, O ( 1 ) O(1) O(1)

cpp 复制代码
void solve(){
   int n,m;cin>>n>>m;
   /*
      想复杂了
      限定n<2e5 直接枚举就可以
      nlogn
   */
   int cnt=n;
   vector<int>st(n+1,0);
   forr(i,1,m){
      int ans=0,a;cin>>a;
      
      if(cnt&&!st[a]){
         if(a==1){// 防止退化为O(n)
            cout<<cnt<<endl;
            cnt=0;
         }
         else{
            for(int j=a;j<=n;j+=a){// logn
               if(st[j])continue;
               else ans++,st[j]=1,cnt--;
            }
            if(ans)cout<<ans<<endl;
            else cout<<"the lights are already on!"<<endl;
         }
      }else{
         cout<<"the lights are already on!"<<endl;
      }
   }
}  

D 思维 贪心

一开始没注意到字典序最小

贪心来想前面的L越多越好,尽量左右横跳

整体方向是向右到头再回来

cpp 复制代码
void solve(){
   int n;cin>>n;
   vector<int>a(n+2,0);
   int sm=0;
   forr(i,0,n){
      cin>>a[i];
      sm+=a[i];
   }
   // 注意还要求字典序最小
   int pos=0;
   string ans;
   // 从右推向左
   vector<int>pre(n+1,0);// 和前一个位置有多少次交换
   pre[n]=a[n];
   reforr(i,0,n-1){
      pre[i]=a[i]-pre[i+1];
      if((i>0&&pre[i]<=0)||(i==0&&pre[i]!=0))return cout<<"Impossible"<<endl,void();
   }
   forr(i,1,n){
      forr(j,1,pre[i]-1){
         ans+="RL";// 左右横跳
      }
      ans+='R';// 向后走
   }
   forr(i,1,n){
      ans+='L';// 回来
   }
   cout<<ans<<endl;
   // while (ans.size()<sm)
   // {
   //    // forr(i,0,n)cout<<a[i]<<' ';cout<<endl;
   //    if(a[pos+1]){
   //       ans+='R';
   //       a[++pos]--;
         
   //       continue;
   //    }else if(pos>0&&a[pos-1]){
   //       ans+='L';
   //       a[--pos]--;
   //    }else{
   //       return cout<<"Impossible"<<endl,void();
   //    }
   // }
   // // cout<<pos<<endl;
   // if(pos!=0)return cout<<"Impossible"<<endl,void();
   // cout<<ans<<endl;
}  

L 基环树 树形dp

cpp 复制代码
const int N = 1e5+10,M=1e5;
const double PI=acos(-1);
const long long mod =998244353, inf = 2e18 ;
vector<int>g[N];
// 并查集找环
int fa[N],vis[N],cnt[N][2];// cnt[][1奶龙/0不是]
int findf(int x){
   return fa[x]=(fa[x]==x?x:findf(fa[x]));
}
int dfs(int now,int f){// 树形dp找答案
   vis[now]=1;
   cnt[now][0]=0;
   cnt[now][1]=1;
   for(auto x:g[now]){
      if(x==f||vis[x])continue;
      dfs(x,now);
      cnt[now][0]+=max(cnt[x][0],cnt[x][1]);
      cnt[now][1]+=cnt[x][0];
   }
   vis[now]=0;// 回复现场
   return cnt[now][0];
}
void solve(){
   /*
      自环 自己说自己是奶龙 必然是说假话的其他生物 
   */
   int n;cin>>n;
   forr(i,1,n)fa[i]=i;
   vector<int>a(n+1);
   vector<pii>cir;
   forr(i,1,n){
      cin>>a[i];
      g[a[i]].push_back(i);
      int fx=findf(a[i]),fy=findf(i);
      if(fx!=fy)fa[fy]=fx;
      else cir.push_back({a[i],i});
   }
   int ans=0;
   for(auto [u,v]:cir){
      ans+=max(dfs(u,0),dfs(v,0));
   }
   cout<<ans<<endl;
}  

G 贪心(找每次操作的收益比率) 二分查找


参考@也不算坏天气 的题解

贪心 让每个增加都能获得最大收益

每次增加前后 商品金额比率
p = 100 + ( t + 1 ) l 100 + t l = 1 + l 100 + t l = 1 + x ′ p=\frac{100+(t+1)l}{100+tl}=1+\frac{l}{100+tl}=1+x' p=100+tl100+(t+1)l=1+100+tll=1+x′

发现t越大 p越小
t = l − 100 x ′ x ′ l t=\frac{l-100x'}{x'l} t=x′ll−100x′ 向下取整 让p尽量比较大

令 x = 1 x ′ x={1\over {x'}} x=x′1, t = x − 100 l t=x-{{100}\over l} t=x−l100

cpp 复制代码
int n,k;
int L[N],t[N];
/*
一开始想用dfs 但是每个点从k中分配 枚举每个城市的t 复杂度爆炸
void dfs(int now,int lst){
   
}
*/
int cal(double x){// 计算给定比率 需要的t总和
   int sm=0;
   forr(i,1,n){
      t[i]=max(0.0,floor(x-100/(L[i]*1.0)));
      sm+=t[i];
   }
   return sm;
}
void solve(){
   cin>>n>>k;
   forr(i,1,n)cin>>L[i];
   double l=0,r=1e6,bestp=l;
   while (r-l>eps)
   {  
      // cout<<l<<' '<<r<<endl;
      double mid=(l+r)/2;
      if(cal(mid)<=k)l=mid,bestp=mid;
      else r=mid;
   }
   int used=cal(bestp);
   /* 用优先队列会损失精度
   priority_queue<pair<double,int>>q;
   forr(i,1,n){
      q.push({(100+(t[i]+1)*L[i])/(100+t[i]*L[i]),i});
   }
   while (used<k)
   {
      auto [pn,id]=q.top();q.pop();
      t[id]++;
      q.push({(100.0+(t[id]+1)*L[id]*1.0)/(100.0+t[id]*L[id]*1.0),id});
      used++;
   }  
   */
   
   while(used<k){
      // 线性查找最优比率
      int id=1;
      double mx=(100.0+(t[id]+1)*L[id]*1.0)/(100.0+t[id]*L[id]*1.0);
      forr(i,2,n){
         double now=(100.0+(t[i]+1)*L[i]*1.0)/(100.0+t[i]*L[i]*1.0);
         if(now>mx){
            mx=now,id=i;
         }
      }
      t[id]++;
      used++;
   }
   double ans=1;
   forr(i,1,n)ans*=(1+1.0*(t[i]*1.0*L[i])/100.0);
   cout<<fixed<<setprecision(8)<<ans<<endl;
}  
相关推荐
@小柯555m2 小时前
算法(字母异位词分组)
java·开发语言·算法·leetcode
故事和你912 小时前
洛谷-算法2-1-前缀和、差分与离散化2
开发语言·数据结构·算法·深度优先·动态规划·图论
贾斯汀玛尔斯2 小时前
每天学一个算法--DFS / BFS
算法·深度优先·宽度优先
郝学胜-神的一滴2 小时前
epoll 边缘触发 vs 水平触发:从管道到套接字的深度实战
linux·服务器·开发语言·c++·网络协议·unix
cpp_25012 小时前
P1877 [HAOI2012] 音量调节
数据结构·c++·算法·动态规划·题解·洛谷·背包dp
dragen_light2 小时前
1.ROS2-Install
c++·python·ros
Gary Studio2 小时前
基于PMSM理论研究加实践
算法
不知名的老吴2 小时前
编程初体验之句柄的概念及使用示例
c++
木子墨5162 小时前
LeetCode 热题 100 精讲 | 矩阵与图论进阶篇:矩阵置零 · 螺旋矩阵 · 旋转图像 · 搜索二维矩阵 II · 岛屿数量 · 腐烂的橘子
c++·算法·leetcode·矩阵·力扣·图论