Codeforces Round #404 (Div. 2) DE
昨晚玩游戏竟然不小心错过了CF。。我是有多浪啊。 今天总算趁着下课时间补了,感觉最后两题还是挺有意思的,写个题解。
D:
题目大意:
给出一个括号序列,问有多少个子序列 是k个'(' + k个')' 这样的形式。 n<=200000
解法:
对于每个'('的位置,计算以它为最右边的'('的合法子序列数。 假设它左边(包括它)有$l$个'(', 右边有 $r$个')' , 如果子序列的长度2k, 那么
方案数有$\binom{l-1}{k-1} * \binom{r}{k}= \binom{l-1}{l-k} * \binom{r}{k}$
这个式子对$k$求和是 $\binom{l+r-1}{l}$ 可以预处理阶乘O(1)计算出。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",ans);
71 return 0;
72 }
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就跑完了?
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",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\n";
109 printf("%I64d\n",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 }
Every day is meaningful, keeping learning!