• Codeforces Round #404 (Div. 2) DE


    昨晚玩游戏竟然不小心错过了CF。。我是有多浪啊。 今天总算趁着下课时间补了,感觉最后两题还是挺有意思的,写个题解。 

    D:

    题目大意:

    给出一个括号序列,问有多少个子序列 是k个'(' + k个')' 这样的形式。        n<=200000

     

    解法:

    对于每个'('的位置,计算以它为最右边的'('的合法子序列数。 假设它左边(包括它)有$l$个'(', 右边有 $r$个')' ,  如果子序列的长度2k, 那么

    方案数有$inom{l-1}{k-1} * inom{r}{k}= inom{l-1}{l-k} * inom{r}{k}$

    这个式子对$k$求和是  $inom{l+r-1}{l}$  可以预处理阶乘O(1)计算出。

    代码:

     1 #include <iostream>
     2 #include <string>
     3 #include <cstring>
     4 #include <map>
     5 #include <cmath>
     6 #include <set>
     7 #include <bitset>
     8 using namespace std;
     9 
    10 typedef long long ll;
    11 typedef pair<int,int> pii;
    12 
    13 #define N 400010
    14 #define X first
    15 #define Y second
    16 
    17 const int INF=1<<30;
    18 const int Mod=1000000007;
    19 int ans;
    20 char s[N];
    21 int fac[N],fac_inv[N];
    22 
    23 
    24 int Power(int x,int p)
    25 {
    26     int res=1;
    27     for (;p;p>>=1)
    28     {
    29         if (p&1) res=1ll*res*x%Mod;
    30         x=1ll*x*x%Mod;
    31     }
    32     return res;
    33 }
    34 
    35 int C(int n,int m)
    36 {
    37     if (m==0) return 1;
    38     if (n==0) return 0;
    39     int res=1ll*fac[n]*fac_inv[m]%Mod;
    40     return 1ll*res*fac_inv[n-m]%Mod;
    41 }
    42 
    43 int l[N],r[N];
    44 
    45 int main()
    46 {
    47     //freopen("in.in","r",stdin);
    48     //freopen("out.out","w",stdout);
    49     
    50     fac[0]=fac_inv[0]=1;
    51     for (int i=1;i<N;i++) 
    52     {
    53         fac[i]=1ll*fac[i-1]*i%Mod;
    54         fac_inv[i]=Power(fac[i],Mod-2);
    55     }
    56     int n; scanf("%s",s+1);
    57     n=strlen(s+1);
    58     
    59     for (int i=1;i<=n;i++) l[i]=l[i-1]+(s[i]=='(');
    60     for (int i=n;i>=1;i--) r[i]=r[i+1]+(s[i]==')');
    61     
    62     for (int i=1;i<=n;i++)
    63     {
    64         if (s[i]!='(') continue;
    65         if (!r[i]) continue;
    66         ans+=C(l[i]+r[i]-1,l[i]);
    67         if (ans>=Mod) ans-=Mod;
    68     }
    69     
    70     printf("%d
    ",ans);
    71     return 0;
    72 }
    View Code

    E:

    题目大意:

    一开始有一个1-n的排列,然后每次操作交换两个数,每次询问逆序对数。        n<=200000,Q<=50000

    解法:

    假设我们交换了a[l],a[r], 那么逆序对数如何改变呢?

    首先逆序对数会减少[l+1,r-1]这个区间里 比a[r]大的数  和 比a[l]小的数。

    然后会增加[l+1,r-1]这个区间里 比a[r]小的数  和 比a[l]大的数。

    因此我们需要快速计算某个区间里有多少个数比x大的。

    我的做法是分块,每个块维护一个树状数组即可。 复杂度比较悬,换了几次块的大小,极限数据本地跑要10s,但是CF机子2s就跑完了?

    代码:

      1 By lzw4896s, contest: Codeforces Round #404 (Div. 2), problem: (E) Anton and Permutation, Accepted, #
      2  #include <iostream>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <map>
      6 #include <set>
      7 #include <cmath>
      8 
      9 using namespace std;
     10 
     11 typedef long long ll;
     12 #define N 200010
     13 
     14 
     15 int n,m,block;
     16 int v[N],id[N];
     17 
     18 inline int Lowbit(int x){return x&-x;}
     19 
     20 struct BIT
     21 {
     22     int c[N];
     23     void Insert(int x,int v)
     24     {
     25         while (x<=n)
     26         {
     27             c[x]+=v;
     28             x+=Lowbit(x);
     29         }
     30     }
     31     int Sum(int l,int r)
     32     {
     33         if (l>r) return 0;
     34         int res=0,x=r;
     35         while (x)
     36         {
     37             res+=c[x];
     38             x-=Lowbit(x);
     39         }
     40         x=l-1;
     41         while (x)
     42         {
     43             res-=c[x];
     44             x-=Lowbit(x);
     45         }
     46         return res;
     47     }
     48 }tree[460];
     49 
     50 int Query(int l,int r,int low,int high)
     51 {
     52     int res=0;
     53     if (id[r]-id[l]<=1)
     54     {
     55         for (int i=l;i<=r;i++) res+=(v[i]>=low && v[i]<=high);
     56         return res;
     57     }
     58     for (int i=l;i<=block*id[l];i++) res+=(v[i]>=low && v[i]<=high);
     59     for (int i=block*(id[r]-1)+1;i<=r;i++) res+=(v[i]>=low && v[i]<=high);
     60     for (int i=id[l]+1;i<=id[r]-1;i++) res+=tree[i].Sum(low,high);
     61     return res;
     62 }
     63 
     64 int main()
     65 {
     66     ///freopen("in.in","r",stdin);
     67     //freopen("out.out","w",stdout);
     68     
     69     int Q,l,r; ll ans=0; 
     70     scanf("%d%d",&n,&Q);
     71     if (n>5000) block=2500;
     72     else block=500;
     73     for (int i=1;i<=n;i++)  v[i]=i;
     74     //block=4;
     75 
     76     for (int i=1;i<=n;i+=block)
     77     {
     78         int j=min(n,i+block-1); m++;
     79         for (int k=i;k<=j;k++)
     80         {
     81             id[k]=m; 
     82             tree[m].Insert(k,1);
     83         } 
     84     }
     85     while (Q--)
     86     {
     87         scanf("%d%d",&l,&r);
     88         if (l==r) 
     89         {
     90             printf("%I64d
    ",ans);
     91             continue;
     92         }
     93         if (l>r) swap(l,r);
     94         if (v[l]>v[r]) ans--;
     95         else ans++;
     96         tree[id[l]].Insert(v[l],-1);
     97         tree[id[r]].Insert(v[r],-1);
     98         if (r-l>1)
     99         {
    100             ans-=Query(l+1,r-1,v[r]+1,n);
    101             ans-=Query(l+1,r-1,1,v[l]-1);
    102             ans+=Query(l+1,r-1,1,v[r]-1);
    103             ans+=Query(l+1,r-1,v[l]+1,n);
    104         } 
    105         swap(v[l],v[r]);
    106         tree[id[l]].Insert(v[l],1);
    107         tree[id[r]].Insert(v[r],1);
    108         //cout<<"eee
    ";
    109         printf("%I64d
    ",ans);
    110         //for (int i=1;i<=n;i++) cout<<v[i]<<" ";
    111         //cout<<endl;
    112         /*for (int i=1;i<=m;i++)
    113         {
    114             for (int j=1;j<=n;j++) cout<<tree[i].Sum(j,j)<<" ";
    115             cout<<endl;
    116         }*/
    117     }
    118 
    119     
    120     return 0;
    121 }
    View Code
  • 相关阅读:
    LA 6621 /ZOJ 3736 Pocket Cube 打表+暴力
    UVA 10273
    UVA 10158 并查集的经典应用
    CodeForces 382B 数学推导
    UVA 10806 最小费用最大流
    UVA 10330 最大流
    图论:匹配与覆盖+独立集 团与支配集
    sdut oj 操作系统实验--SSTF磁盘调度算法【操作系统算法】
    【转载】单调队列学习
    poj 3006 Dirichlet's Theorem on Arithmetic Progressions【素数问题】
  • 原文地址:https://www.cnblogs.com/vb4896/p/6561040.html
Copyright © 2020-2023  润新知