zoukankan      html  css  js  c++  java
  • bzoj4531 [Bjoi2014]路径

    Description

     

    在一个N个节点的无向图(没有自环、重边)上,每个点都有一个符号,
    可能是数字,也可能是加号、减号、乘号、除号、小括号。你要在这个图上数
    一数,有多少种走恰好K个节点的方法,使得路过的符号串起来能够得到一
    个算数表达式。路径的起点和终点可以任意选择。
    所谓算数表达式,就是由运算符连接起来的一系列数字。括号可以插入在
    表达式中以表明运算顺序。
    注意,你要处理各种情况,比如数字不能有多余的前导0,减号只有前面
    没有运算符或数字的时候才可以当成负号,括号可以任意添加(但不能有空括
    号),0可以做除数(我们只考虑文法而不考虑语意),加号不能当正号。
    例如,下面的是合法的表达式:
    -0/0
    ((0)+(((2*3+4)+(-5)+7))+(-(2*3)*6))
    而下面的不是合法的表达式:
    001+0
    1+2(2)
    3+-3
    --1
    +1
    ()

    Input

    第一行三个整数N,M,K,表示点的数量,边的数量和走的节点数。
    第二行一个字符串,表示每个点的符号。
    接下来M行,每行两个数,表示一条边连的两个点的编号。
    1≤N≤20,0≤M≤N×(N-1)/2,0≤K≤30

    Output

    输出一行一个整数,表示走的方法数。这个数可能比较大,你只需要输出
    它模1000000007的余数即可。

    dp,状态表示为四维:(第几步,表达式末尾所在的点,未匹配的左括号数,表达式是否以一个0结尾)

    #include<cstdio>
    int n,m,k;
    char s[64];
    int es[1000],enx[1000],e0[24],ep=2;
    int f[36][36][36][2];
    bool o[256],num[256];
    bool ed[24][24];
    const int P=1e9+7;
    inline void add(int&a,int b){
        a=(a+b)%P;
    }
    int main(){
        scanf("%d%d%d%s",&n,&m,&k,s+1);
        for(int i=0,a,b;i<m;i++){
            scanf("%d%d",&a,&b);
            ed[a][b]=ed[b][a]=1;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i;j++)if(ed[i][j]){
                es[ep]=j;enx[ep]=e0[i];e0[i]=ep++;
                if(i==j)continue;
                es[ep]=i;enx[ep]=e0[j];e0[j]=ep++;
            }
        }
        for(int i='0';i<='9';i++)num[i]=1;
        o['+']=o['-']=o['*']=o['/']=1;
        for(int i=1;i<=n;i++){
            char c=s[i];
            if(c=='(')f[1][i][1][0]=1;
            if(num[c])f[1][i][0][c=='0']=1;
            if(c=='-')f[1][i][0][0]=1;
        }
        for(int t=2;t<=k;t++){
            for(int w=1;w<=n;w++){
                char c1=s[w];
                for(int j=e0[w],u;j;j=enx[j]){
                    u=es[j];
                    char c2=s[u];
                    for(int k=0;k<18;k++){
                        if(c2=='('){
                            if(num[c1]||c1=='-')add(f[t][w][k][c1=='0'],f[t-1][u][k][0]);
                            else if(c1=='(')add(f[t][w][k+1][0],f[t-1][u][k][0]);
                        }else if(c2==')'){
                            if(o[c1])add(f[t][w][k][0],f[t-1][u][k][0]);
                            else if(c1==')'&&k)add(f[t][w][k-1][0],f[t-1][u][k][0]);
                        }else if(o[c2]){
                            if(num[c1])add(f[t][w][k][c1=='0'],f[t-1][u][k][0]);
                            else if(c1=='(')add(f[t][w][k+1][0],f[t-1][u][k][0]);
                        }else if(num[c2]){
                            if(num[c1])add(f[t][w][k][0],f[t-1][u][k][0]);
                            else if(o[c1])add(f[t][w][k][0],f[t-1][u][k][0]),add(f[t][w][k][0],f[t-1][u][k][1]);
                            else if(c1==')'&&k>0)add(f[t][w][k-1][0],f[t-1][u][k][0]),add(f[t][w][k-1][0],f[t-1][u][k][1]);
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)if(s[i]==')'||num[s[i]])add(ans,f[k][i][0][0]),add(ans,f[k][i][0][1]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Android—应用程序开机自启
    Android—简单的仿QQ聊天界面
    Android—关于自定义对话框的工具类
    Android—基于GifView显示gif动态图片
    Android—ListView条目背景为图片时,条目间距问题解决
    Android—自定义开关按钮实现
    FileProvider的使用
    Android 7.0新特性
    Android SDK自带调试优化工具
    Android监视器概述
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5397064.html
Copyright © 2011-2022 走看看