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%\n",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的场的压轴题?感觉确实挺难的一个计数题。

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

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

逃~

 

posted @ 2020-02-12 17:10  Zzqf  阅读(227)  评论(0编辑  收藏  举报