zoukankan      html  css  js  c++  java
  • 2020牛客寒假算法基础集训营4

    https://ac.nowcoder.com/acm/contest/3005#question

    比赛里感觉比前几天难?也许吧。又是经典2小时理论...后面墨迹出一题。

    补题发现还是有可做的题没出?

    或许是题解写的太好,实际上我想不到嘻嘻。

    记录一下补题和思维。

    B.括号序列  栈模拟即可。

    A.欧几里得  斐波那契?我感觉我是找规律做的,就加上去就行了。不过我还是做完了B才想到的A的做法的。

    C.子段乘积   叫啥尺取来着,经典按K尺取。这里需要注意特判0有在的区间,这里白WA了两发,有点急,发现没特判0有点晚,0的逆元还是0,左右更新的时候都会有影响。

    我的做法是,标记0出现的位置,尺取更新的时候只 * 右边的非0,* 左边的非0逆元,同时特判离上个0的位置距离是否满足k。 

    D.子段异或   刚开始无从下手,以为要止步于此。后来沉思了十几分钟,又看了标签有前缀和,就感觉 区间异或和 的性质实际上有点像区间加减法。就是你一段的异或,和前缀的一段异或如果相同,那么剪掉前缀(实际上是再和前缀做一遍异或,异或自己就是0,就没了),剩下的部分就是异或和为0的一段。

    然后分别维护个前缀和,map记录统计一下就过了,

    E.最小表达式 看了一眼,虽然很裸,但没看清不存在0,是1~9的数字,感觉不太好码,就去看了F,后来发现大家E都过得很快,那我也做E。发现不存在0,无需特判。

    贪心分配数字即可,然后我还模拟了string数字的加法,实际上似乎没有必要,不过我写起来倒还挺快的,越来越熟练了哈哈哈。

    实际上直接从低位几个数字加起来,维护进位,一次性搞定就可以了。不过我想的是从高位分配的小的数字开始的,思维就固化成了字符串加法。可以注意一下。

    F.树上博弈  看到这个,感觉又止步于此。树上的题,有一说一做的真的少,看到树就慌。玩了样例开始以为距离为2的点对的数量,目的就是把牛妹赶到叶子上动不了。

    还画了第三个样例30个点的图,差不多确认就是树上距离点对,立马找点分治板子改。。。然后改不来,以为止步于此,但我又感觉按层数统计就行了,用不着点分治啊。后来过了题的同学的提示,是距离为偶数的点对的数量。

    按层数统计过了。不过T了好多发,由于我的统计复杂度应该过大(每个点向下找能不大伐)。搞了2个小时似乎。

    点分治似乎更加实用于树上带边权的图?不带边权按层数直接搞距离就行了。

    实际上题解的做法,因为奇数+奇数=偶数,偶数+偶数=偶数,树上距离为偶数的点对,就是层数为奇数的点的数量,和偶数的点的数量内部各自的 排列 A (n,2)即可。

    然后树上距离为奇数的点对数量你也会了吧。

    由于这题树的边给的方式十分的特别,下次看到应当注意,甚至不需要建边dfs,省了O(n)的一遍dfs统计层数,就可以算出每个点所在的层数。

    G.音乐鉴赏

    概率期望题,感觉自己也挺弱的,每次都是赛中懵逼题,赛后傻逼题。好像有点夸张,反正赛中很少做出来就是了。

    这题告诉我们一个道理:大胆出来,此处@ajj。

    有两种做法:

    1.二分,实际上更好想,似乎不需要推式子就可以上手码,没往这里想,我有问题,事实上这种正面比较难求,给定答案就能够反向check的题,应该往这里想的。这里check就是算在这个p下,最终的优秀率的期望与目标10%的差异。 而最终的优秀率的期望 ->  就是优秀的人数的期望 / 总人数 -> 优秀人数的期望就是每个人优秀概率的和 -> 

    每个人的优秀概率怎么求? 你优秀所需要的随机分数  y= (90 - score*(1-p))/p,你需要随机分数>=y,那你的优秀概率就是 1 - (   (90 - score*(1-p))/p  ) /90,因为随机分数均匀分布嘛,1- (<=y的分数概率) 就是 >=y 的分数的概率。

    然后就结束了。就贴个二分的代码吧。

     1 #include <bits/stdc++.h>
     2 #ifndef ONLINE_JUDGE
     3 #define debug(x) cout << #x << ": " << x << endl
     4 #else
     5 #define debug(x)
     6 #endif
     7 using namespace std;
     8 typedef long long ll;
     9 const int maxn=2e5+7;
    10 const int inf=0x3f3f3f3f;
    11 const int mod=1e9+7;
    12  
    13 int n,a[maxn];
    14  
    15 double check(double p)
    16 {
    17     double sum=0;
    18     for(int i=0;i<n;++i)
    19     {
    20         double need = (90-a[i]*(1-p))/p;
    21         sum += 1-need/90;
    22     }
    23     return sum/n;
    24 }
    25 int main()
    26 {
    27     scanf("%d",&n);
    28     for(int i=0;i<n;++i) scanf("%d",&a[i]);
    29     double l=0,r=1;
    30     double ans;
    31     for(int i=0;i<100;++i)
    32     {
    33         double m=(l+r)/2;
    34         if(check(m)>0.1)
    35         {
    36             l=m;
    37             ans=m;
    38         }
    39         else r=m;
    40     }
    41     printf("%.2f%
    ",100*ans);
    42     return 0;
    43 }
    View Code

    2.直接正面推,需要设变量(实际上跟我们做数学题一样,就是需要用形式化的语言去解,而不是空想,比如我~),我这里码一下 就是 每个人优秀的概率是啥? 

      一个人优秀的式子(好有喜感): (score)*(1-p)+y*(p)>=90,  也就是  y >= (90-(score)*(1-p))   (score代表他的平时分,y代表随机到的论文分)

    其实跟上面那个式子一样  ,也就是y>=这个式子的概率是啥?  就是这个玩意儿: 1 - (   (90 - score*(1-p))/p  ) /90,就是每个人的优秀率,

    最后化简,对每个人求和,就会出来能够O(1)出答案的式子了。

    希望自己记住这种概率期望题要敢于设变量,建式子想?

    H.坐火车

    比赛了看了几眼,树状数组啊,啥?要相同颜色的车厢数乘起来?

    我只能想到,对每个车厢的每个l,r区间需要分别query然后乘起来,这不是复杂度爆炸嘛。不会做。。。然后就滚去想G了。

    实际上如果再深入思考下,发现从一个车厢到下一个车厢,改变的东西十分的有限,就上个的col和当前的col而已。这样的转移变化十分的精简。

    树状数组维护每个颜色的组合对数,然后从左到右每个车厢减去当前颜色在左边的总数量,(因为当前这个点颜色的对左边的贡献全没了),然后加上这个当前颜色在右边的总数量(因为当前这个点的颜色对右边的组合的贡献需要加上),同时维护左右区间各种当前颜色的数量即可。

    下次见希望会做,主要是这个转移,需要深入想下,每次从上一次来的变化。

     1 #include <bits/stdc++.h>
     2 #ifndef ONLINE_JUDGE
     3 #define debug(x) cout << #x << ": " << x << endl
     4 #else
     5 #define debug(x)
     6 #endif
     7 using namespace std;
     8 typedef long long ll;
     9 const int maxn=1e6+7;
    10 const int inf=0x3f3f3f3f;
    11 const int mod=1e9+7;
    12 
    13 struct BIT
    14 {
    15     ll sum[maxn];
    16     void clear(){memset(sum,0,sizeof sum);}
    17     int lowbit(int x){return x & (-x);}
    18     void add(int x,int val)
    19     {
    20         while (x < maxn)
    21         {
    22             sum[x] += val;
    23             x += lowbit(x);
    24         }
    25     }
    26     ll query(int x)
    27     {
    28         if (x <= 0) return 0;
    29         ll res = 0;
    30         while (x)
    31         {
    32             res += sum[x];
    33             x -= lowbit(x);
    34         }
    35         return res;
    36     }
    37     ll query(int l,int r){return query(r) - query(l -1);}
    38 }bit;
    39 
    40 
    41 int col[maxn],l[maxn],r[maxn];
    42 
    43 int rsum[maxn],lsum[maxn];
    44 int main()
    45 {
    46     ios::sync_with_stdio(false);
    47     cin.tie(0);
    48     int n;
    49     cin>>n;
    50     for(int i=1;i<=n;++i)
    51     {
    52         cin>>col[i]>>l[i]>>r[i];
    53         rsum[col[i]]++;
    54     }
    55     for(int i=1;i<=n;++i)
    56     {
    57         rsum[col[i]]--;
    58         bit.add(col[i],-lsum[col[i]]);
    59         cout<<bit.query(l[i],r[i])<<' ';
    60         lsum[col[i]]++;
    61         bit.add(col[i],rsum[col[i]]);
    62     }
    63     cout<<endl;
    64     return 0;
    65 }

    I.匹配星星

    比赛里看了,以为这是三维偏序经典题?CDQ分治???翻了以前做的,然后发现题目不一样,然后不会做。

    实际上完全没注意到范围,z是0~1,然后就变成了贪心傻逼题了。

    按其中一维,比如x,sort一下,按x循环的顺序搞,z=0是我们的目标群体,z=1去找配对,显然找比当前y小的最大的一个y最好,因为要把小的y让给别人呀,找到要删除。

    于是用类set的multiset维护,因为y可能会重嘛,每次lowerbound二分查一下即可。

    这个题解里讲的很清楚,就不赘述(逃~)。

    https://ac.nowcoder.com/discuss/365889?type=101&order=0&pos=8&page=3

     1 #include <bits/stdc++.h>
     2 #ifndef ONLINE_JUDGE
     3 #define debug(x) cout << #x << ": " << x << endl
     4 #else
     5 #define debug(x)
     6 #endif
     7 using namespace std;
     8 typedef long long ll;
     9 const int maxn=2e5+7;
    10 const int inf=0x3f3f3f3f;
    11 const int mod=1e9+7;
    12  
    13 struct point
    14 {
    15     int x,y,z;
    16 }p[maxn];
    17 bool cmp(point a,point b)
    18 {
    19     return a.x<b.x;
    20 }
    21  
    22 int main()
    23 {
    24     ios::sync_with_stdio(false);
    25     cin.tie(0);
    26     int n;
    27     cin>>n;
    28     for(int i=0;i<n;++i) cin>>p[i].x>>p[i].y>>p[i].z;
    29     sort(p,p+n,cmp);
    30     multiset<int>st;
    31     multiset<int>::iterator it;
    32     int ans=0;
    33     for(int i=0;i<n;++i)
    34     {
    35         if(p[i].z==1)
    36         {
    37             it=st.lower_bound(p[i].y);
    38             if(it==st.begin()) continue;
    39             ans++;
    40             it--;
    41             st.erase(it);
    42         }
    43         else
    44             st.insert(p[i].y);
    45     }
    46     cout<<ans<<endl;
    47     return 0;
    48 }

    J.二维跑步

    比赛里完全没看,第一次没人ak的场的压轴题?感觉确实挺难的一个计数题。

    看题解,前面的都还好,虽然很牛逼,但可以理解。就最后一段,没懂 错位加法是啥,目前还没搞懂。以后也不一定搞懂。。。代码循环内最后一部分不知道在干啥。

    他写的取模运算函数感觉还不错噢。

    逃~

  • 相关阅读:
    VS2008 编译出错 fatal error C1859: unexpected precompiled header error, simply rerunning the compiler might fix this problem
    解析XML出错,无法创建DOMDocument对象
    strncpy, strncpy_s
    Mongodb: Sort operation used more than the maximum 33554432 bytes of RAM
    node-cache
    【Boost】boost::string_algo详解2——find相关函数
    Compiler Error: Function call with parameters that may be unsafe
    fopen和fopen_s用法的比较
    fopen_s遇到的一个问题
    Data type conversion in MongoDB
  • 原文地址:https://www.cnblogs.com/Zzqf/p/12299761.html
Copyright © 2011-2022 走看看