码迷,mamicode.com
首页 > 其他好文 > 详细

jddxl

时间:2019-09-06 12:55:08      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:system   sys   while   printf   none   gif   diff   end   name   

遇到一个简单$dp$,觉得很棒在此写下题解

真的非常简单,

jddxl

有一个长度$n$括号序列(只有$"()"$ ),给定其中长度为$m$一段,求满足括号匹配方案数

$n,m<=1e6$ $n-m<=4000$

题解

 

性质:我们发现一个合法匹配序列左扩号时刻比右括号多(显然),最后左扩号数量等于右括号数量

设$f[i][j]$表示长度为$i$序列,左扩号比右括号多$j$个方案数

那么类似的设$g[i][j]$为右括号比左扩号多$j$的方案数

(其实$f$和$g$值完全一样)

 

转移非常简单

当前括号可能是$($则贡献$f[i][j]=f[i-1][j-1]$为$)$则$f[i][j]=f[i-1][j+1]$

总贡献$f[i][j]=f[i-1][j-1]+f[i-1][j+1]$

类似的$g[i][j]=g[i-1][j-1]+g[i-1][j+1]$

那么思考统计答案

其实也非常简单

枚举第一段长度$i$,第一段左扩号比右括号多$j$,设给定序列左扩号比右括号多$j$

$ans=\sum\limits_{i=1}^{i<=n-m} \sum\limits_{j=0}^{j<=i} f[i][j]*g[(n-m)-i][j+tot]$

注意判是否合法

代码

技术图片
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 4040
const ll mod=1e9+7;
char c[2020202];
ll f[A][A];
ll tot,mint,n,m,ans;
int main(){
//    freopen("da.in","r",stdin); freopen("ans.bf","w",stdout);
    scanf("%lld%lld",&n,&m);
    scanf("%s",c+1);
    for(ll i=1;i<=m;i++){
        if(c[i]==()
            tot++;
        else tot--;
        if(i==1) mint=tot;
        else mint=min(mint,tot);
    }
    f[0][0]=1;
    for(ll i=1;i<=n-m;i++){
        for(ll j=0;j<=i;j++){
            if(j==0) f[i][j]=f[i-1][j+1];
            else f[i][j]=(f[i-1][j+1]+f[i-1][j-1])%mod;
        }
    }
    for(ll i=0;i<=n-m;i++){
        for(ll j=0;j<=i;j++){
            if(j+mint>=0&&j+tot<=n-m)
                ans=(ans+f[i][j]*f[(n-m)-i][j+tot]%mod)%mod;
        }
    }
    printf("%lld\n",ans);
}
View Code

我没数据,也没法提交,和$std$对拍了一下

下面是我的数据生成及对拍

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     system("g++ bf.cpp -o bf");
 5     system("g++ sol.cpp -o sol");
 6     system("g++ da.cpp -o da");
 7     int rp=0;
 8     while(++rp){
 9         cout<<rp<<" ";
10         system("./da");
11         system("./sol");
12         system("./bf");
13         if(system("diff -B -b ans.sol ans.bf")){
14             puts("WA");
15             while(1);
16         }
17         puts("AC");
18     }
19 }
对拍
技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     freopen("da.in","w",stdout);
 5     srand(time(NULL));
 6     
 7     int m=rand()%10000+300;
 8     int c=rand()%m+1;
 9     while(m-c>2000){
10         c=rand()%m+1;
11     }
12     cout<<m<<" "<<c<<endl;
13     for(int i=1;i<=c;i++){
14         if(rand()%2){
15             printf("(");
16         }
17         else printf(")");
18     }
19     cout<<endl;
20 }
数据生成

 

jddxl

标签:system   sys   while   printf   none   gif   diff   end   name   

原文地址:https://www.cnblogs.com/znsbc-13/p/11474038.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!