力扣 第493场周赛(A~D)

A:3870. 统计范围内的逗号

三位一个逗号,问1~n总共有多少个逗号。

数据范围较小,可直接模拟。

 1 class Solution {
 2 public:
 3     int countCommas(int n) {
 4         int ans=0;
 5         for(int i=1;i<=n;i++){
 6             int t=i;
 7             while(t/1000>0){
 8                 ans++;
 9                 t/=1000;
10             }
11         }
12         return ans;
13     }
14 };

B:3871. 统计范围内的逗号 II

A的升级版,升级了数据范围,不能直接模拟了。

赛时写了个很复杂的,后面听了题解,横看成岭侧成峰啊,以乘每1000为一个阶段,当前阶段内每一个数的逗号数为c,那么下一个阶段的逗号数为c+1。

 1 typedef long long LL;
 2 class Solution {
 3 public:
 4     long long countCommas(long long n) {
 5         LL ans=0;
 6         LL c=0,m=1;
 7         while(m*1000<=n){
 8             ans+=(1000*m-1-m+1)*c;
 9             m*=1000;
10             c++;
11         }
12         ans+=(n-m+1)*c;
13         return ans;
14     }
15 };

C:3872. 替换最多一个元素后的最长等差子数组
前后缀分解,注意除了pre[i-1]+1+suf[i+1]和pre[i-1]+1两种情况之外,还需要考虑两边d不相同,但是右边的第一个元素能够匹配左边的d的情况,反过来同理。

 1 class Solution {
 2 public:
 3     int longestArithmetic(vector<int>& nums) {
 4         int n=nums.size();
 5         auto calc=[&](vector<int> t){
 6             vector<int> res(n,0);
 7             res[0]=1;
 8             res[1]=2;
 9             for(int i=2;i<n;i++){
10                 if(t[i]+t[i-2]==t[i-1]*2)
11                     res[i]=res[i-1]+1;
12                 else
13                     res[i]=2;
14             }
15             return res;
16         };
17         vector<int> pre=calc(nums);
18         reverse(nums.begin(),nums.end());
19         vector<int> suf=calc(nums);
20         reverse(suf.begin(),suf.end());
21         int ans=(*max_element(pre.begin(),pre.end()))+1;
22         if(ans>=n)
23             return n;
24         reverse(nums.begin(),nums.end());
25         for(int i=1;i<n-1;i++){
26             int d2=nums[i+1]-nums[i-1];
27             if(d2%2)
28                 continue;
29             bool ok_left=i>1 && (nums[i-1]-nums[i-2]==d2/2);
30             bool ok_right=i+2<n && (nums[i+2]-nums[i+1]==d2/2);
31             if(ok_left && ok_right)
32                 ans=max(ans,pre[i-1]+1+suf[i+1]);
33             else if(ok_left)
34                 ans=max(ans,pre[i-1]+2);
35             else if(ok_right)
36                 ans=max(ans,suf[i+1]+2);
37         }
38         return ans;
39     }
40 };

 

D:3873. 添加一个点后可激活的最大点数
一眼并查集,将具有相同x或相同y的点都连成一个集合,新加一个点可以任选两个集合激活。那么就选最大的两个,在并查集的同时计算一下cnt即可。

 1 class Solution {
 2 public:
 3     int maxActivated(vector<vector<int>>& pts) {
 4         int n=pts.size();
 5         vector<int> f(n);
 6         vector<int> cnt(n,1);
 7         for(int i=0;i<n;i++)
 8             f[i]=i;
 9         function<int(int)> find=[&](int x){
10             if(f[x]!=x)
11                 f[x]=find(f[x]);
12             return f[x];
13         };
14         auto merge=[&](int a,int b){
15             int fa=find(a),fb=find(b);
16             if(fa!=fb){
17                 f[fb]=fa;
18                 cnt[fa]+=cnt[fb];
19             }
20         };
21         map<int,vector<int>> xg,yg;
22         for(int i=0;i<n;i++){
23             int x=pts[i][0],y=pts[i][1];
24             xg[x].push_back(i);
25             yg[y].push_back(i);
26         }
27         for(auto [k,v]:xg){
28             int t=v[0];
29             for(int i=1;i<v.size();i++){
30                 merge(t,v[i]);
31             }
32         }
33         for(auto [k,v]:yg){
34             int t=v[0];
35             for(int i=1;i<v.size();i++){
36                 merge(t,v[i]);
37             }
38         }
39         vector<int> s;
40         vector<bool> vis(n,false);
41         for(int i=0;i<n;i++){
42             int t=find(i);
43             if(!vis[t]){
44                 s.push_back(cnt[t]);
45                 vis[t]=true;
46             }
47         }
48         sort(s.begin(),s.end(),[](int a,int b){return a>b;});
49         if(s.size()==0)
50             return 1;
51         else if(s.size()==1)
52             return s[0]+1;
53         else
54             return s[0]+s[1]+1;
55     }
56 };

 

posted on 2026-03-16 17:25  greenofyu  阅读(1)  评论(0)    收藏  举报