牛客编程巅峰赛S2第10场 - 青铜&白银&黄金 & 牛客编程巅峰赛S2第12场 - 青铜&白银&黄金 & 看 钻石&王者题目

 

感想放在最后

 

10th场

1. 没有准备好类Topcoder提交 -> 应该准备一个模板,比如 Solution sol; sol.xxx,更加节省时间

A 尝试总结容易漏东西,这种题直接莽就完事了

比赛中有考虑总结,然后就时间浪费了

 

B 第一眼有点像冒泡排序(直接写就难受了……)

  还是先在纸上写写比较好

 

C

 

1.有经验的第一眼想到LowBit(树状数组)

2.初学者打表找规律(事实上会快点)

3.还有f(1)+...+f(2*i) 与 f(1)+...+f(i) 的规律挺好的~

分治思想

4.对应3,

感觉 f(1)+...+f(2^i) 与 f(1)+...+f(2^(i-1)) 的规律更容易想

5.强行打表。学到一招。sqrt(n)复杂度(如果允许);或者打k*1e8的数值。

这应该是写得最快的……

 

D

这题挺好的

 

这题这么多人过,但我觉得感觉不好想,也许是他们套路见识多了。下面2^20是个提示,这……

 

把数字(二进制)拆位,单独与,但是求关于1的连通块。

O(n*log(p))

 

遇到数的->联想是否二进制拆位。其它比如数位DP

 

赛后我想了树分治,

于是有集合A的数分别与集合B的数求与,仔细一想还可以把某个集合里的数汇合起来,不过也要二进制拆位。

 

看到有网友 多动手 用的是树形DP,

每增加一个子节点,与之前的点进行交互,做到最后,就相当于两两进行交互,感觉挺巧妙的,代码也短。

 

 

 

===================================

 

 12th

A

C++占尽优势,如是说也

我的itoa炸了,没有然后……

其实while也挺快的(所以手速场就不应该尝试弄itoa这种自己也不熟,没有把握的东西

to_string:to_string(s): ?->string

sprintf(str_1,"?",?)

甚至感觉高手是手打

或者干脆用python写

cb有问题:https://blog.csdn.net/u013271326/article/details/79613898(比赛呢?所以要学sprintf)

 

C++

 1 class Solution {
 2 public:
 3     /**
 4      * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 5      * 判断x是不是好数
 6      * @param x int整型 待判断的数
 7      * @return bool布尔型
 8      */
 9     bool judge(int x) {
10         //return to_string(x)[-1]==to_string(x)[0];
11         string s=to_string(x);
12         ///负值不行,坑~ Python可负
13         //return s[-1]==s[0];
14         return s[s.size()-1]==s[0];
15     }
16 };

 

 1 class Solution {
 2 public:
 3     /**
 4      * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 5      * 判断x是不是好数
 6      * @param x int整型 待判断的数
 7      * @return bool布尔型
 8      */
 9     bool judge(int x) {
10         char s[100];
11         sprintf(s,"%d",x);
12         return s[strlen(s)-1]==s[0];
13     }
14 };

 

Python

class Solution:
    def judge(self , x ):
        # write code here
        x=str(x)
        return x[0]==x[-1]



sol=Solution()
print(sol.judge(1))
print(sol.judge(123))

 

TypeError: 'int' object is not subscriptable

没有有下标

 

B

一眼直觉DP题

一个序列,一个数的状态只与前一个有关系

O(n^2)

赛后有人说树状数组,O(nlogn);有的O(n^2logn)超了

实际上,我看了大部分前排的代码,都是先固定中间,然后再选左右

数目为N

n=N-2

1*n+2*(n-1)+...+n*1=(1+2+...+n)*n-(1*2+2*3+...+(n-1)*n)=1/6*n*(n+1)*(n+2),实在不明白为什么能过??!

n=5000,value=20833332500

当然固定了中间之后,也可以树状数组哦,从左往右加,从右往左加,也是O(nlogn)

 

这就是典型的OIer思想啊,一开始竟然不往这里想

 

另外,vector卡了很久……

 

赛后修改

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <string>
 6 #include <vector>
 7 #include <algorithm>
 8 #include <iostream>
 9 using namespace std;
10 #define ll long long
11 const int maxn=5e3+10;
12 
13 const ll mod=1000000007;
14 
15 
16 
17 class Solution {
18 public:
19     /**
20      * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
21      *
22      * @param arr int整型vector
23      * @param a int整型
24      * @param b int整型
25      * @return int整型
26      */
27 
28 
29 
30     int countTriplets(vector<int>& arr, int a, int b) {
31         // write code here
32         int f[maxn][2];
33         int i,j,x,y,n=arr.size();
34         ll sum=0;
35         for (i=0;i<n;i++)
36         {
37             for (j=0;j<i;j++)
38             {
39                 if (abs(arr[i] - arr[j])<=a)
40                     f[i][0]+=1;
41                 if (abs(arr[i] - arr[j])<=b)
42                     f[i][1]+=f[j][0];
43             }
44             sum+=f[i][1];
45         }
46         return sum%mod;
47     }
48 };
49 
50 //int main()
51 //{
52 //    Solution sol;
53 //    vector<int> vec={7,1,8,9,0};
54 ////    vector<int> vec={10,20,30,40,50};
55 ////    vector<int> vec={10,10,10,10,10};
56 //    cout<<sol.countTriplets(vec,3,3);
57 //
58 ////    cout<<sol.countTriplets([7,1,8,9,0],3,3);
59 ////    //不行
60 //
61 //    return 0;
62 //}
63 
64 //int main()
65 //{
66 //    int n=5000,i;
67 //    ll sum=0;
68 //    for (i=1;i<=n;i++)
69 //        sum+=i*(n-i);
70 //    cout<<sum;
71 //    ///20833332500
72 //}

 

比赛时

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <string>
 6 #include <vector>
 7 #include <algorithm>
 8 #include <iostream>
 9 using namespace std;
10 #define ll long long
11 const int maxn=5e3+10;
12 
13 const ll mod=1000000007;
14 
15 
16 
17 class Solution {
18 public:
19     /**
20      * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
21      *
22      * @param arr int整型vector
23      * @param a int整型
24      * @param b int整型
25      * @return int整型
26      */
27 
28 
29 
30     int countTriplets(vector<int>& arr, int a, int b) {
31         // write code here
32         int f[maxn][2];
33         vector<int>::iterator it,ti;
34         int i,j,x,y;
35         ll sum=0;
36         for (it=arr.begin(),i=0;it!=arr.end();it++,i++)
37         {
38             f[i][0]=1;
39             x=*it;
40             for (ti=arr.begin(),j=0;ti!=it;ti++,j++)
41             {
42                 y=*ti;
43 //                if (abs((*it) , (*ti))<=a)
44                 if (abs(x - y)<=a)
45                     f[i][1]+=f[j][0];
46 //                if (abs(*it , *ti)<=b)
47                 if (abs(x - y)<=b)
48                 {
49                     f[i][2]+=f[j][1];
50 
51                 }
52             }
53             sum+=f[i][2];
54         }
55         return sum%mod;
56     }
57 };

 

 

 

C

问题思想:

z 0 -z 规律

拆分的思想,独立

 

我的做法:

数值扩大一倍,2z 0 -2z

每个数 z 0 -z

也有方法,是一开始全部-z(预处理),然后选就+z

 

 问题:

1.cout了一发(所以一定要线下判一下……)

2.vector……

3.中途傻逼想网络流了。

看到很多人也是想图论,什么负边,拆点……

 

我的3发错误

1. 没认真造样例,不太认真,蜜汁自信(事后发现错误还很多的)

2. 无脑cout(之前有没有注释int main ,所以一定要线上(自判)、线下都判一下……)

3. 为了避免数组出问题,把数组大小改为1e6,进行了初始化,过了

但是神奇的是,

1e5 无初始化 70%

1e6 无初始化 过

1e5 初始化 过

数组放在外面 / 数组放在类里面而不是函数里面 1e5 无初始化

贼神奇!

建议好好了解一下评测机~~~

 

怎么还是认为数组要初始化(一直怕,因为有前车之鉴)

之前担心数组是否不能放在外面,经测试,不用担心(可以,尽量放外面,减去初始化什么的,避免各种神奇bug)

 

/**
networkflow
->dijkstra

budui?

同时奏响的额外优美程度是z,同时不奏响则为-z,其他情况为0
???
a value z

**/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define ll long long
const int maxn=1e6+10;

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * @param n int整型
     * @param m int整型
     * @param a int整型vector
     * @param b int整型vector<vector<>>
     * @return long长整型
     */
    long long wwork(int n, int m, vector<int>& a, vector<vector<int> >& b) {
        // write code here

//        int fx[maxn];
//        int fy[maxn][3],i,j;
//        ll;

//        vector<vector<int> >::iterator it2;
//        vector<int>::iterator it1;
//
//        for (it1=a.begin(),j=0;it1!=a.end();it1++,j++)
//            fx[j]=*it1;
//        for (it2=b.begin(),i=0;it2!=b.end();it2++,i++)
//            for (it1=it2.begin(),j=0;it1!=it2.end();it1++,j++)
//                fy[i][j]=*it1;

//        for (i=0;i<n;i++)
////            cout<<fx[i]<<endl;
//            cout<<a[i]<<endl;
//        for (i=0;i<m;i++)
//            for (j=0;j<3;j++)
//                cout<<b[i][j]<<endl;

//                cout<<fy[i][j]<<endl;

//        return ;

        int i,j;
        ll f[maxn],sum=0;

        ///both no -2z
        ///both yes 2z
        ///same 0
        ///

//        for (i=0;i<n;i++)
//            f[i]=0;

        ///if zouxiang
        for (i=0;i<m;i++)
            for (j=0;j<=1;j++)
            {
                f[b[i][j]]+=b[i][2];
//                cout<<b[i][j]<<" "<<b[i][2]<<endl;
            }

//        cout<<endl;

        for (i=1;i<=n;i++)
        {
//            cout<<f[i]+2*a[i-1]<<" "<<-f[i]<<endl;
            sum+=max( f[i]+2*a[i-1] , -f[i] );
        }

        return sum/2;
    }
};

//int main()
//{
//    Solution sol;
//
////    vector<int> vec1={-10,-10};
//////    vector<int> vec1={10,10};
////    vector<vector<int> > vec2;
////    vec2.push_back(vector<int>());
////    vec2[0].push_back(1);
////    vec2[0].push_back(2);
////    vec2[0].push_back(5);
////    cout<<sol.wwork(2,1,vec1,vec2);
//
////    vector<int> vec1={3,5};
//////    vector<int> vec1={10,10};
////    vector<vector<int> > vec2;
////    vec2.push_back(vector<int>());
////    vec2[0].push_back(1);
////    vec2[0].push_back(2);
////    vec2[0].push_back(7);
////    cout<<sol.wwork(2,1,vec1,vec2);
//
//
//
////    vector<int> vec1={-10,-10,-10};
//
//    vector<int> vec1={10,10,10};
//
//    vector<vector<int> > vec2;
//    vec2.push_back(vector<int>());
//    vec2[0].push_back(1);
//    vec2[0].push_back(2);
//    vec2[0].push_back(10);
//
//    vec2.push_back(vector<int>());
//    vec2[1].push_back(1);
//    vec2[1].push_back(3);
//    vec2[1].push_back(1000);
//
//    vec2.push_back(vector<int>());
//    vec2[2].push_back(1);
//    vec2[2].push_back(2);
//    vec2[2].push_back(-100);
//    cout<<sol.wwork(3,3,vec1,vec2);
//    return 0;
//}


D

题意理解

  • 首先是求最长的距离下的两点

  • 这两点在什么时候最短(旋转卡壳)

  • 这两个点在什么时候距离(二次函数,三分)

题意弄懂后,就没问题了……

 

 

===================================

 

赛前准备

另一个桌面(打完后转回来!)

文件创建快捷方式

模板

  加上

  #include <string>

  #include <vector>

  但是太多也……(有万能代码)

现在才发现有使用示例自测 示例1示例2示例3,可以手点……

 

===================================

 

vector

1. 可以直接vec[i],vec[i][j],大小vec.size(),感觉用vector<int>::iterator,vector<int>::reverse_iterator就……

但是调试麻烦

2.     cout<<sol.countTriplets([7,1,8,9,0],3,3);
    //不行

vector<int> vec={7,1,8,9,0}; //ok 但是感觉很别扭,有更快的方法?

为什么它那样输入([])就可以?

3.

https://www.cnblogs.com/xiaoxi666/p/6843211.html

c++中常用的vector容器作为参数时,有三种传参方式,分别如下(为说明问题,用二维vector):

  • function1(std::vector<std::vector<int> > vec),传值
  • function2(std::vector<std::vector<int> >& vec),传引用
  • function3(std::vector<std::vector<int> >* vec),传指针

注意,三种方式分别有对应的const形式,不在此讨论。

三种方式对应的调用形式分别为:

  • function1(vec),传入值
  • function2(vec),传入引用
  • function3(&vec),传入地址

三种方式的效果分别为:

  • 会发生拷贝构造
  • 不会发生拷贝构造
  • 不会发生拷贝构造

4. vector转数组

std::copy(vec.begin(), vec.arr(), arr);

 1 int main()
 2 {
 3     vector<int> vec={1,2,3};
 4     int arr[10];
 5 //    copy(vec.begin(),vec.end(),arr);
 6 //    arr=vec;
 7     for (int i=0;i<3;i++)
 8         cout<<arr[i]<<" ";
 9     return 0;
10 }

 

5. 功能

push_back

insert

erase

 

6.

c++ vector 调试

 

https://www.pianshen.com/article/7164927754/

查看vector变量A当中元素的方法有2种:
1.在“添加查看”中输入 A[0];
2.在“添加查看”中输入 *(&A[0]);

 

查看vector数组B[5]当中元素的方法也有2种:
1.在“添加查看”中输入 B[3[0];
2.在“添加查看”中输入 *(&B[3][0]);

 

 

 

==================

 

调试:

虽然可以直接注释掉 int main()

 

别人的方法 https://ac.nowcoder.com/acm/contest/view-submission?submissionId=46228366

 1 #define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
 2 void debug_out() { cerr << endl; }
 3   
 4 template <typename Head, typename... Tail>
 5 void debug_out(Head H, Tail... T) {
 6   cerr << " " << to_string(H);
 7   debug_out(T...);
 8 }
 9 
10 #ifdef DEBUG
11 XXX
12 #endif

 

 

===================================

 

科研散心过来打打,分别获得了10th场 rank 10th(3/3),12th场 21th(3/3)的成绩,赚了一个奖品,还行~

主要讲述

  1. 用类Topcoder提交和vector的各种心酸历程,感觉很多基本的代码不会用,比如to_string那些(很久不用就忘了,加上本身自己就不擅长),然后就……

  2. 赛后思考的改代码,使写得更快

  3. 多种思路的交碰

 

感觉

  1. 青铜&白银&黄金 感觉挺多S*B题(说实话第一个是奔着奖品去的),后来发现也有不少耳目一新的题目,学习了。听题解讲述发现不少题目与大众(Non-OI/ICPCer)思维不同

  2. 最后一场最后一题的处惊不乱,自我感觉还是不错的,有点ShengHua的感觉~

  3. 之后应该不会为了奖品打This Competition吧(吧吧)(感觉钻石&王者最后一题也不是太好过),不为五斗米折腰(逃),要勇闯CF Div1啊啊啊,不要畏缩在CF Div 2(希望自己水平能高点吧)。

  4. 在研究生中,

    更加体会到实际问题 & 理论研究部。

    有时也不追求时间,能做出来就好(工程)。

    也有非最完美算法,比如近似算法,启发式搜索。

    对于算法的研究会更加体系化,感觉没有ICPC那么碎和追求比赛。

    自己对于算法的学习,会更加契合于自己研究课题,并追求于学习更有挑战的知识和思想,而不是像之前不断巩固算法和提高手速,然后有时做题有些重复和难度低,感觉这样学习算法不太好,会学得比较慢和没有激情,挥霍青春。现在心态比较放松,感觉大学时有时心态复杂,有时打比赛经常没有发挥应有的水平。

    逐渐感觉到数学的重要性,所以好好学习数学吧。

posted @ 2020-12-24 13:22  congmingyige  阅读(185)  评论(0编辑  收藏  举报