• 10 15


    考挂了 中午和某位强者去吃饭他说他状态不好 可能会挂 结果又是快Ak 了 然后我挂了 这就是 强者定律吧说着我要挂了 然后别人挂了...

    今天得分 64 分T1 52 分 T3 12 分。丢人 and 很难受 也让我看清了生活的真相。世界上只有一种英雄主义就是 认清生活的真相之后依然还热爱生活。

    有m个括号坏掉了 考虑组合 16分 爆搜 32 分dp 如何dp?这个dp 和普通的 括号匹配方案数即卡特兰数n^2递推不一样因为不需要记录还有多少个右括号已经用过了。

    但是m个括号坏掉了 所以右括号也要记录个数 怎样能把整个括号序列都表达出来呢? 很有趣的问题 可以设 f[i][j][k] 表示已经形成了j个匹配 有效左括号为j 还剩下k个右括号的方案数。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<queue>
    #include<iomanip>
    #include<cctype>
    #include<cstdio>
    #include<deque>
    #include<utility>
    #include<cmath>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<vector>
    #include<algorithm>
    #include<stack>
    #include<map>
    #include<set>
    #include<bitset>
    #define INF 1000000000
    #define ll long long
    #define db double
    #define pii pair<ll,ll>
    #define mk make_pair
    #define us unsigned
    #define mod 998244353
    #define R register
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int MAXN=2000010,maxn=110;
    int n,m,N,w,s;
    ll jc[MAXN],inv[MAXN],in[MAXN],sum,cnt;
    ll f[maxn][maxn][maxn];//f[i][j][k]成功匹配了i个 此时还有j个有效左括号 还有k个右括号
    inline ll ksm(ll b,ll p)
    {
        ll ans=1;
        while(p)
        {
            if(p&1)ans=ans*b%mod;
            b=b*b%mod;
            p=p>>1;
        }
        return ans;
    }
    inline void prepare()
    {
        jc[0]=1;
        for(int i=1;i<=N;++i)jc[i]=jc[i-1]*i%mod;
        inv[N]=ksm(jc[N],mod-2);
        for(int i=N-1;i>=0;--i)inv[i]=inv[i+1]*(i+1)%mod;
        for(int i=1;i<=N;++i)in[i]=inv[i]*jc[i-1]%mod;
    }
    inline int Ca(int a,int b)//求Ca(n,m) a!/(a-b)!/b!/b+1
    {
        return (((jc[a]*inv[b]%mod)*inv[a-b])%mod)*in[b+1]%mod;
    }
    inline int C(int a,int b)//求 C(n,m)
    {
        return ((jc[a]*inv[b]%mod)*inv[a-b]%mod);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        freopen("excatalan.in","r",stdin);
        freopen("excatalan.out","w",stdout);
        n=read();m=read();N=n<<1;w=n-m;
        prepare();
        if(!m){printf("%d
    ",Ca(N,n));return 0;}
        if(n<=1000)
        {
            f[0][0][n]=1;
            for(R int i=0;i<=w;++i)
                for(R int j=0;j<=n;++j)
                    for(R int k=n;k>=0;--k)
                    {
                        if(i+j<n)f[i][j+1][k]=(f[i][j+1][k]+f[i][j][k])%mod;
                        if(k&&!j)f[i][j][k-1]=(f[i][j][k-1]+f[i][j][k])%mod;
                        if(j&&k)f[i+1][j-1][k-1]=(f[i+1][j-1][k-1]+f[i][j][k])%mod;
                    }
            printf("%lld
    ",f[w][m][0]);
            return 0;
        }
        return 0;
    }
    View Code

    100分的话考虑折线法。我理解不够深刻 这里不敢赘述,

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template<typename T>inline void read(T &x) {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x*=f;
    } 
    const ll mod=998244353;
    ll fac[2002002],inv[2002002],n,m,ans;
    inline ll pow(ll a,ll b) {
        ll res=1;
        while(b) {
            if(b&1) res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    inline ll C(ll n,ll m) {
        if(m>n) return 0;
        if(m<0) return 0;
        if(n<0) return 0;
        return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    inline ll c(ll n) {return (C(2ll*n,n)-C(2ll*n,n+1)+mod)%mod;}
    ll exctl(int n,int m) {return (C(2ll*n,n)-C(2*n,n-m-1)+mod)%mod;}
    int main() {
        freopen("excatalan.in","r",stdin);
        freopen("excatalan.out","w",stdout);
        read(n); read(m); 
        fac[0]=1;
        for(int i=1;i<=2*n;i++) {
            fac[i]=fac[i-1]*i;
            fac[i]%=mod;
        }
        inv[2*n]=pow(fac[2*n],mod-2);
        for(int i=2*n-1;i>=0;i--) {
            inv[i]=inv[i+1]*(i+1);
            inv[i]%=mod;
        }
        if(m==0) ans=c(n);
        else ans=(exctl(n,m)-exctl(n,m-1)+mod)%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    样例有点毒瘤其实 但是影响不大 原地爆炸qwq.算了十几分钟 觉得很毒瘤。

    但是还是可以写的 考虑dp f[i][j] 表示以i为根的子树种大小为j的联通块期望混乱度 。 转移有点繁琐 这里不再赘述 是n^3的。

    然后不会了 咕掉 不太能理解这个东西的思想。

    考虑8分爆搜  然后观察题目显然的是序列必然为 奇数 且 有一定的 性质例如一个数一定比上上一个数大或者小什么的。

    f[i][j][k] 考虑到了 第i个数且上一个数字是j 上上数字是k 的方案数。转移n^3 显然可以滚动数组。

    不懂 咕掉。

  • 相关阅读:
    今年暑假不AC
    亲和数
    改革春风吹满地
    hdu人见人爱A^B
    男人必看的10部电影
    富人和穷人之间的经典差异
    今日十句英文
    看透一个人起码要看的。
    人生经典20句
    解决ubuntu中mysql中文乱码问题
  • 原文地址:https://www.cnblogs.com/chdy/p/11690470.html
Copyright © 2020-2023  润新知