zoukankan      html  css  js  c++  java
  • Codeforces Round #361 (Div. 2)

      我以为这场是昨天没做完的那场= =,结果是以前没做完的一场。。前3题以前做过了。也懒得再看一遍了= =。虽然前面的题感觉再做一遍也不一定做的出的样子- -。不过D和E都是好题,补这场不亏。

      D题,题意是问有多少区间,这段区间里面,在a数组中的max和在b数组中的min是相同的。做法是枚举左端点,考虑到max和min随着区域的增长都是单调的,因此可以二分右端点找出这个区间是不是可行。二分的复杂度是log,寻找给定区间的min或max的复杂度如果用线段树的话复杂度要再加上一个log,有被卡的可能性,因此二分以后考虑用st表进行O(1)寻找即可。这是我第一次写st表,留个代码当作模板。代码如下:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <iostream>
     5 using namespace std;
     6 const int N = 200000 + 5;
     7 typedef long long ll;
     8 
     9 int st_min[N][32], st_max[N][32];
    10 int preLog[N];
    11 int n;
    12 int a[N],b[N];
    13 void init()
    14 {
    15     preLog[1] = 0;
    16     for(int i=2;i<=n;i++)
    17     {
    18         preLog[i] = preLog[i-1];
    19         if((1 << preLog[i] + 1) == i) preLog[i]++;
    20     }
    21     for(int i=n;i>=1;i--)
    22     {
    23         st_max[i][0] = a[i];
    24         st_min[i][0] = b[i];
    25         for(int j=1;(i+(1<<j)-1)<=n;j++)
    26         {
    27             st_min[i][j] = min(st_min[i][j-1], st_min[i+(1<<j-1)][j-1]);
    28             st_max[i][j] = max(st_max[i][j-1], st_max[i+(1<<j-1)][j-1]);
    29         }
    30     }
    31 }
    32 int query_min(int l,int r)
    33 {
    34     int len = r - l + 1, k = preLog[len];
    35     return min(st_min[l][k], st_min[r-(1<<k)+1][k]);
    36 }
    37 int query_max(int l,int r)
    38 {
    39     int len = r - l + 1, k = preLog[len];
    40     return max(st_max[l][k], st_max[r-(1<<k)+1][k]);
    41 }
    42 
    43 int main()
    44 {
    45     cin >> n;
    46     for(int i=1;i<=n;i++) scanf("%d",a+i);
    47     for(int i=1;i<=n;i++) scanf("%d",b+i);
    48     init();
    49     ll cnt = 0;
    50     for(int i=1;i<=n;i++)
    51     {
    52         int L = i, R = n;
    53         int temp1 = -1;
    54         while(L <= R)
    55         {
    56             int mid = L + R >> 1;
    57             int max_a = query_max(i, mid);
    58             int min_b = query_min(i, mid);
    59             if(max_a == min_b) {temp1 = mid; R = mid - 1;}
    60             else if(max_a > min_b) R = mid - 1;
    61             else L = mid + 1;
    62         }
    63         if(temp1 != -1)
    64         {
    65             int temp2 = -1;
    66             L = i, R = n;
    67             while(L <= R)
    68             {
    69                 int mid = L + R >> 1;
    70                 int max_a = query_max(i, mid);
    71                 int min_b = query_min(i, mid);
    72                 if(max_a == min_b) {temp2 = mid; L = mid + 1;}
    73                 else if(max_a > min_b) R = mid - 1;
    74                 else L = mid + 1;
    75             }
    76             cnt += temp2 - temp1 + 1;
    77         }
    78     }
    79     cout << cnt << endl;
    80     return 0;
    81 }
    D

      E题,有n个线段,选出其中的k段,求它们的交集的贡献和。也是一个很经典的题目。既然是算贡献,那么扫一遍,如果当前的线段被覆盖的次数超过了k次,那么就用组合数计算一遍贡献即可。注意线段要用map来离散化;组合数用的是仓鼠的模板。代码如下:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <iostream>
     5 #include <map>
     6 using namespace std;
     7 typedef long long ll;
     8 const int N = 200000 + 5;
     9 const int MOD = (int)1e9 + 7;
    10 int F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘
    11 void init(){
    12     inv[1] = 1;
    13     for(int i = 2; i < N; i ++){
    14         inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
    15     }
    16     F[0] = Finv[0] = 1;
    17     for(int i = 1; i < N; i ++){
    18         F[i] = F[i-1] * 1ll * i % MOD;
    19         Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
    20     }
    21 }
    22 int comb(int n, int m){//comb(n, m)就是C(n, m)
    23     if(m < 0 || m > n) return 0;
    24     return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
    25 }
    26 
    27 int n,k;
    28 
    29 int main()
    30 {
    31     init();
    32     cin >> n >> k;
    33     map<int,int> M;
    34     for(int i=1;i<=n;i++)
    35     {
    36         int l,r; scanf("%d%d",&l,&r);
    37         M[l] ++; M[r+1] --;
    38     }
    39     int last = M.begin()->first;
    40     int temp = 0;
    41     ll ans = 0;
    42     for(map<int,int>::iterator it=M.begin();it!=M.end();it++)
    43     {
    44         ll num = it->first - last;
    45         if(temp >= k) ans += comb(temp, k) * num % MOD;
    46         ans %= MOD;
    47         temp += it->second;
    48         last = it->first;
    49     }
    50     cout << ans << endl;
    51     return 0;
    52 }
    E

      

  • 相关阅读:
    OCP-1Z0-053-200题-54题-679
    OCP-1Z0-053-200题-55题-632
    OCP-1Z0-053-200题-78题-655
    底层框架PhoneGap
    用Dw CS6运行静态页面出问题
    JavaScript split()函数
    Java Web项目报错总结
    dojo报错总结
    FusionCharts中图的属性的总结归纳
    dojo表格的一些属性
  • 原文地址:https://www.cnblogs.com/zzyDS/p/6359990.html
Copyright © 2011-2022 走看看