zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练第二场部分

    2020牛客多校训练第二场

    出题数 2 --- D题(真水题) 和 F题(滑动窗口)

    D、Duration

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    int main()
    {
      int ah , am , as , bh , bm , bs ;
      scanf("%d:%d:%d" , &ah , &am , &as) ;
      scanf("%d:%d:%d" , &bh , &bm , &bs) ;
      ll a = ah * 3600 + am * 60 + as ;
      ll b = bh * 3600 + bm * 60 + bs ;
      cout << abs(a - b) << endl ;
      return 0 ;
    }
    /*
    */
    

    F Fake Maxpooling

    在这里插入图片描述
    整个矩阵很好求,然后要求求每个k * k矩阵的最大值,我先预处理出来每个k * 1的最大值,然后按照上图滑动窗口的时候,左面丢出一个k * 1, 右面多出一个k * 1, 直接按照滑动窗口的模式就可以,然后这是一行的, 然后枚举每行, 做滑动窗口就行了

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    int a[5010][5010] , ans = 0 , maxn[5010][5010] ;
    int q[5010] ;
    int main()
    {
      int n = in() , m = in() , k = in() ;
      for(int i = 0; i < n ;i ++ ) {
        for(int j = 0; j < m ;j ++ ) {
          a[i][j] = 1ll * (i + 1) * (j + 1) / __gcd(i+ 1 ,1 +  j) ;
        }
      }
     
      for(int j = 0; j < m ;j ++ ) {
        int hh = 0 , tt = -1 ;
        for(int i = 0; i < n ;i ++ ) {
          if(i - k + 1 > q[hh]) ++ hh ;
          while(hh <= tt && a[i ][j] >= a[q[tt]][j]) -- tt ;
          q[++ tt] = i  ;
          if(i + 1 >= k) maxn[i - k + 1][j] = a[q[hh]][j] ;
        }
     
      }
       ll ans = 0 ;
       for(int i = 0 ;i < n ;i ++ ) {
         int hh = 0 , tt = -1 ;
         for(int j = 0 ;j < m ;j ++ ) {
           if(j - k + 1 > q[hh]) ++ hh ;
           while(hh <= tt && maxn[i][j] >= maxn[i][q[tt]]) -- tt ;
           q[++ tt] = j ;
           if(j + 1 >= k) {
             ans += 1ll * maxn[i][q[hh]]  ;
           }
         }
       }
       cout << ans << endl ;
      return 0 ;
    }
    /*
    */
    

    补题系列

    C Cover the Tree

    一条链 , 两个端点, 并且这两个端点都是度为1的点 , 要求最小的数量,就是(n + 1) / 2, 如果n是偶数的话, 就两两配对,如果是奇数的话,再多一条链。那么怎么配对呢。这个看的大佬的代码是这样写的。
    ![](https://img-blog.csdnimg.cn/20200713185331709.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Nwbm9veXNlZWQ=,size_16,color_FFFFFF,t_70
    边(u , v) , u < v, 最终的图也就是上图 , 就直接小标号的叶子节点匹配大标号的叶子节点

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    int deg[N] , res[N];
    int main()
    {
      int n = in() ;
      for(int i = 1 , a ,b ;i < n ;i ++ ) {
        a = in() , b = in() ;
        deg[a] ++ , deg[b] ++ ;
      }
      int ans = 0 ;
      for(int i = 1; i <= n ;i ++ )
       if(deg[i] == 1)
        res[++ ans] = i ;
      cout << (ans + 1) / 2 << endl ;
      for(int i = 1; i <= (ans + 1) / 2;i ++ )
       cout << res[i] << " " << res[ans / 2 + i] << endl ;
      return 0 ;
    }
    /*
    */
    
    

    J.Just Shuffle

    此题相当于一个单位置换群e,通过置换 P置换群 k次得到一个置换群A

    [e * P^k = A\ e*P = A^{k^{-1}}\P = A^{k^{-1}} ]

    然后将i和a[i]连接起来,就会得到一些环,每个环就是一个置换群,也就是每个A,然后求A的逆元就行了

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    int vis[N] , a[N] , b[N] , res[N] ;
    int main()
    {
      int n = in() , k = in() ;
      for(int i = 1; i <= n ;i ++ ) a[i] = in() ;
      for(int i = 1; i <= n ;i ++ ) {
        if(vis[i]) continue ;
        int pos = i ;
        vector<int> ans ;
        while(!vis[pos]) ans.push_back(pos) , vis[pos] = 1 , pos = a[pos] ;
        int size = ans.size() ;
        int t = 0 ;
        while(t < size) {
          if(1ll * t * k % size == 1) break ;
          t ++ ;
        }
        for(int i = 0 ;i < size ;i ++ )
         res[ans[i]] = ans[(i + t) % size] ;
      }
      for(int i = 1; i <= n ;i ++ ) cout << res[i] << " " ;
      puts("") ;
      return 0 ;
    }
    /*
    */
    
    

    B、Boundary

    解法一:算圆心坐标

    枚举两点 , 加上原点,总共三点,三点定圆

    [(x - x[i]) ^ 2 + (y - y[i]) ^ 2 = x ^ 2 + y ^ 2 ]

    [(x - x[j]) ^ 2 + (y - y[j]) ^ 2 = x ^ 2 + y ^ 2 ]

    [x = frac{b[j] * (x[i] ^ 2 + y[i] ^ 2) - b[i] * (x[j] ^ 2 + y[j] ^ 2)}{2x[i] * y[j] - 2 * x[j] * y[i]} ]

    [y = frac{x[j] * (x[i] ^ 2 + y[i] ^ 2) - x[i] * (x[j] ^ 2 + y[j] ^ 2)}{2x[j] * y[i] - 2 * x[i] * y[j]} ]

    先判断一下分母是否为0 , 记得用long long

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-7 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    ll x[N] , y[N] ;
    double get(int i){
      return 1ll * x[i] * x[i] + y[i] * y[i] ;
    }
    vector<pair<double , double>> ans ;
    int main()
    {
      int n = in() ;
      for(int i = 1; i <= n ;i ++ ) x[i] = in() , y[i] = in() ;
      int res = 0 ;
      for(int i = 1; i <= n ;i ++ ) {
        ans.clear() ;
        for(int j = 1 ; j <= n ;j ++ ) {
          ll  yy = x[j] * get(i) - x[i] * get(j) ;
          ll t = 2 * x[j] * y[i] - 2 * x[i] * y[j] ;
            if(t == 0) continue ;
          ll xx = y[j] * get(i) - y[i] * get(j) ;
          ans.push_back({(double)xx / (-t) , (double) yy / t}) ;
        }
        sort(ans.begin() , ans.end()) ;
        int cnt = 1 , maxn = 0 ;
        for(int i = 1 ; i < ans.size() ;i ++ )
         {
           if(fabs(ans[i].x - ans[i - 1].x) < esp && fabs(ans[i].y - ans[i - 1].y) < esp) cnt ++;
           else cnt = 1 ;
           maxn = max(maxn , cnt) ;
         }
        res = max(res , maxn + 1) ;
      }
      cout << res << endl ;
      return 0 ;
    }
    /*
    */
    
    

    解法二:算夹角

    在这里插入图片描述
    这两个角一定相同,同时为了避免重复,在上图中二选一,也就是选择一个判断标准,op向量*oa向量 < 0, 也可以选择大于0 , 或者选择ap * ao, 然后算夹角acos(dot(ap , ao) / (len(ap) * len(ao))) , 最后随便统计一下, 不过精度好象要调到1e-9, 在1e-8都是不能完全通过的(也可能写的程序不太对)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef long long ll ;
    const double esp = 1e-7, pi = acos(-1) ;
    typedef pair<double , double> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    PII a[N] ;
    double dot(PII a , PII b){
      return a.x * b.x + a.y * b.y ;
    }
    double cross(PII a , PII b){
      return a.x * b.y - a.y * b.x ;
    }
    double c[N] ;
    double len(PII a){
      return sqrt(a.x * a.x + a.y * a.y) ;
    }
    double calc(PII a , PII b){
      double lena = len(a) , lenb = len(b) ;
      return acos(dot(a , b) / (lena * lenb)) ;
    }
    int main()
    {
      int n = in() ;
      for(int i = 1; i <= n ;i ++ ) cin >> a[i].x >> a[i].y ;
      int ans = 0 ;
      for(int i = 1; i <= n ;i ++ ) {
        int cnt = 0 ;
        for(int j = 1; j <= n ;j ++ ) {
          PII op = a[i] , oa = a[j] ;
          PII ap = {a[j].x - a[i].x , a[j].y - a[i].y} , ao = {-a[j].x ,- a[j].y} ;
          if(cross(op , oa) < 0) c[++ cnt] = calc(ap , ao) ;
        }
        sort(c + 1 , c + cnt + 1) ;
        int maxn = 0 , res = 0 ;
        double t = 0 ;
        for(int i = 1; i <= cnt ;i ++ ) {
          if(fabs(c[i] - t) < esp) res ++ ;
          else res = 1 , t = c[i] ;
          maxn = max(maxn , res) ;
        }
        ans = max(ans , maxn) ;
      }
      cout << ans + 1 << endl ;
      return 0 ;
    }
    /*
    */
    
    

    A.All with Pairs

    看到这题的第一个想法就是先预处理出来每个字符串的所有后缀,用map存起来,然后再枚举每个字符串的前缀,判断有多少个之前map存储的hash值个数,但是发现题目要求是要求最大,而不是求所有的,上面的这个做法可以将所有符合前缀等于后缀的贡献求出来, 但不能求最大的。然后发现一个小小的性质,kmp算法next数组的经典应用
    在这里插入图片描述
    上图两个字符串匹配中蓝色竖杠之间的是前缀等于后缀的部分,但是是要求最大的,我们接着往下面匹配
    在这里插入图片描述
    突然后面这个绿色之间的匹配的一部分比蓝色部分更大,也就是说当前这个答案更优,那我们就不要前面那个,但是发现
    在这里插入图片描述
    对于黑色曲线,我们发现,1、2、3、4、5号线段字符串部分全部都是相同的,也就是1 和 5是相同的,这不就是kmp里面如果枚举到5部分突然失配了, 会跳到1部分嘛,对于这个性质应用到当前题目上面就是-----题目要求最大,我们就把所有前缀后缀相同的部分都直接算答案,不过面对上图这个情况,我们可以再kmp即将失配的时候,也就是i失配的时候,将next[i]部分的贡献减掉,即h[ne[j]] -= h[j], 这样就在把所有贡献都加上 的同时, 减掉对于当前贡献来说前面贡献比较小的部分,就是最大的贡献 , 即题目所求

    
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    #include <vector>
    #include <map>
    #include <list>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <set>
    #pragma GCC optimize(3 , "Ofast" , "inline")
    using namespace std ;
    #define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
    #define x first
    #define y second
    typedef unsigned long long ll ;
    const double esp = 1e-6 , pi = acos(-1) ;
    typedef pair<int , int> PII ;
    const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 998244353 , base = 131;
    ll in()
    {
      ll x = 0 , f = 1 ;
      char ch = getchar() ;
      while(!isdigit(ch)) {if(ch == '-') f = -1 ; ch = getchar() ;}
      while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
      return x * f ;
    }
    unordered_map<ll , int> mp ;
    void Hash(string s){
      ll res = 0 , p = 1 ;
      for(int i = s.size() - 1; i >= 0 ;i --) {
        res += p * s[i] ;
        p *= base ;
        mp[res] ++ ;
      }
      return ;
    }
    string s[N] ;
    int h[N] , ne[N] ;
    void get(string s){
      for(int i = 2, j = 0 ;i < s.size() ;i ++ ) {
        while(j && s[i] != s[j + 1]) j = ne[j] ;
        if(s[i] == s[j + 1]) j ++ ;
        ne[i] = j ;
      }
      return ;
    }
    int main()
    {
      int n ;
      cin >> n ;
      for(int i = 1; i <= n ;i ++ ) {
        cin >> s[i] ;
        Hash(s[i]) ;
      }
      ll ans = 0 ;
      for(int i = 1; i <= n ;i ++ ) {
        ll res = 0 ;
        for(int j = 0 ;j < s[i].size() ;j ++ ) {
          res = res * base + s[i][j] ;
          h[j + 1] = mp[res] ;
        }
    
        s[i] = " " + s[i] ;
        get(s[i]) ;
        for(int j = 1 ; j < s[i].size() ;j ++ )
         h[ne[j]] -= h[j] ;
    
        for(int j = 1; j < s[i].size() ;j ++ )
         ans = (ans + 1ll * h[j] * j % mod * j % mod) % mod ;
      }
      cout << ans << endl ;
      return 0 ;
    }
    /*
    */
    
    
    

    剩下几题咱也不会

  • 相关阅读:
    初学Java——数组
    Ubuntu下将软件添加到快捷启动栏的问题
    初学Java——方法
    初学Java——选择
    初学Java——常用类之Math笔记
    初学Java——基本程序设计笔记(2)
    初学Java——基本程序设计笔记(1)
    关于IE浏览器里修改元素style属性的问题
    2.22,2.24工作进度
    2.21工作进度
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/13333850.html
Copyright © 2011-2022 走看看