CodeForces 785D Anton and School - 2

枚举,容斥原理,范德蒙恒等式。

先预处理每个位置之前有多少个左括号,记为$L[i]$。

每个位置之后有多少个右括号,记为$R[i]$。

然后枚举子序列中第一个右括号的位置,计算这个括号的第一个右括号的方案数。

即在它左边取$k$个左括号,在右边取$k-1$个右括号都是合法的方案,这个东西可以用范德蒙恒等式化成一个组合数以及容斥原理计算。

范德蒙恒等式:http://blog.csdn.net/acdreamers/article/details/31032763

#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL; 

char s[200010];
long long L[200010],R[200010];
LL fac[200010];
long long mod = 1e9+7;

void init()
{
    int i;
    fac[0] =1;
    for(i =1; i <= 200000; i++)
        fac[i] = fac[i-1]*i%mod;
}
LL pow(LL a, LL b)
{
    LL tmp = a % mod, ans =1;
    while(b)
    {
        if(b &1)  ans = ans * tmp % mod;
        tmp = tmp*tmp % mod;
        b >>=1;
    }
    return  ans;
}
LL C(LL n, LL m)
{
    if(m>n||m<0)return 0;
    return  fac[n]*pow(fac[m]*fac[n-m],mod-2)%mod;
}   

int main()
{
	init();
	scanf("%s",s);
	int len = strlen(s);

	for(int i=1;i<=len;i++)
	{
		L[i] = L[i-1];
		if(s[i-1]==‘(‘) L[i]++;
	}

	for(int i=len;i>=1;i--)
	{
		R[i] = R[i+1];
		if(s[i-1]==‘)‘) R[i]++;
	}

	long long ans = 0;

	for(int i=1;i<=len;i++)
	{
		if(s[i-1]==‘(‘) continue;
		if(L[i]==0) continue;

		long long m,k1,k2;

		m = min(L[i],R[i]);
		if(m==0) k1=1;
		else k1 = C(L[i]+R[i],m);

		m = min(L[i],R[i]-1);
		if(m==0) k2=1;
		else k2 = C(L[i]+R[i]-1,m);

		long long k = (k1-k2+mod)%mod;
		ans = ( ans + k ) %mod;
	}

	printf("%lld\n",ans);

	return 0;
}
时间: 2024-10-24 15:56:54

CodeForces 785D Anton and School - 2的相关文章

CodeForces 785D Anton and School - 2 组合数学

题意: 给你一串括号 问你有多少种匹配的子串 就是前半部分都是'(' 后半部分都是')'的子串 思路: 首先我们预处理 当前位置之前有多少左括号 和 当前位置之后有多少右括号 对于每一个处于i位置的左括号 我们将ans+=C(left[i]+right[i]-1,right[i]-1) 这个式子是C(i-1,left[i]-1)*C(i+1,right[i])化简来的 因为选的数总数是不变的 所以可以化简(?) 就是从左边选i-1个左括号 从右边选i+1个右括号 因为自己是必选的 所以左括号-1

codeforces 785D D. Anton and School - 2

题目链接:http://codeforces.com/problemset/problem/785/D 题意:给你一个只包含'('和')'的字符串,然后问他的子序列中有多少满足前一半是左括号,后一半是右括号. 分析:看到题就想到是组合数学,对于一个左括号,他能影响到的右括号就是他后边的,因此,你需要求前缀和和后缀和,来这样来求组合数.现在我们枚举左括号,当枚举到他时,代表他一定被选,前缀和为n,后缀和为m,然后在他前边选i=0到min(n,m)-1个,在他后边选前边数+1个.然后就是C(n-1,

codeforces 785C Anton and Fairy Tale

题目链接:http://codeforces.com/problemset/problem/785/C 题意:仓库容量是n,一开始是满的,然后每天晚上可以往仓库里装m粮食,最多装到n.然后每天白天有鸟来吃粮食,一只鸟吃1单位.第i天有i只鸟.问你多少天鸟可以把粮食吃完. 分析:一开始读错题,导致wa了两发.如果n<=m的话,只有n只鸟的时候一天把他吃完,输出n.如果m<n的话,前m是肯定吃不完的,m天之后,从1开始计数,就是好比每天白天吃i+m,晚上装m,一天好比加了i.所以可以二分天数,但是

Codeforces 734C Anton and Making Potions(枚举+二分)

题目链接:http://codeforces.com/problemset/problem/734/C 题目大意:要制作n个药,初始制作一个药的时间为x,魔力值为s,有两类咒语,第一类周瑜有m种,每种咒语使制作一个药的时间变成a[i],花费b[i]的魔力,第二类咒语有k种,每种咒语瞬间产生c[i]个药,花费d[i]的魔力,c[i]和d[i]都是不递减的,求最短时间内产生n个药的时间.解题思路:因为c[i]和d[i]都是不降的,所以可以枚举a[i],然后二分查找花费小于t-b[i]的第二类咒语.注

CodeForces 593B Anton and Lines

计算出每条线段在x1处的y坐标和x2处的y坐标. 就下来只要根据每条线段左右两处的y坐标就可以判断是否有交点. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; long long INF=9999999999999999; long long x1,x2; int n; struct X { long long k,b; l

CodeForces 734F Anton and School

位运算. 两个数的和:$A+B=(AandB)+(AorB)$,那么$b[i]+c[i]=n*a[i]+suma$.可以解出一组解,然后再按位统计贡献验证一下. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<v

CodeForces 734B Anton and Digits

贪心.先取$256$,再取$32$. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<

CodeForces 734E Anton and Tree

$dfs$缩点,树形$dp$. 首先将连通块缩点,缩点后形成一个黑白节点相间的树.接下来的任务就是寻找一个$root$,使这棵树以$root$为根,树的高度是最小的(也就是一层一层染色).树形$dp$可以解决这个问题,第一次$dfs$处理子树,第二次$dfs$枚举$root$计算答案. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring>

codeforces 584E Anton and Ira [想法题]

题意简述: 给定一个$1$到$n(n<=2000)$的初始排列以及最终排列 我们每次可以选取位置为$i$和$j$的 并交换它们的位置 花费为$ |i-j| $ 求从初始状态变换到末状态所需最小花费 ----------------------------------------------------------------------------------------------------------- 比赛时这题留了$40min$ 然而自己贪心策略还是有漏洞 结束后看了首页的官方题解 感