• LOJ #2731 [JOI2016春季合宿]Solitaire (DP、组合计数)


    题目链接

    https://loj.ac/problem/2731

    题解

    首先一个很自然的思路是,设(dp[i][j])表示选了前(i)列,第(2)行第(i)列的格子是第(j)个被填上的。
    还要加个第三维(0/1),表示第(2)行第(i)列不是/是这一列最后一个被填上的(这决定了它是被上下填上还是被左右填上)。
    转移: 若第(2)行第(i)列是棋子,则所有的都转移到(f[i][0][0]).
    (1) (0 ightarrow 0), 两个互不影响,可以从任意的(j')(f[i][j'][0])转移过来,组合数选出顺序。
    (2) (1 ightarrow 0), ((2,i))要在((2,i-1))之前选,可以从大于当前的(j')转移过来,同样用组合数选出顺序。
    (3) (0 ightarrow 1), ((2,i))要在((2,i-1))之后选。但是这里要求((2,i))早于((1,i))((3,i))中的至少一个,因此需要分类讨论。我的代码里第一个转移是((2,i))比上下两个(如果存在)都晚,第二个转移是((2,i))早于上下两个中的一个。

    代码

    #include<bits/stdc++.h>
    #define llong long long
    #define mkpr make_pair
    using namespace std;
     
    const int N = 2000;
    const int P = 1e9+7;
    char a[3][N+3];
    llong dp[N+3][N*3+3][2];
    llong fact[N*3+3],finv[N*3+3];
    int n;
     
    llong quickpow(llong x,llong y)
    {
        llong cur = x,ret = 1ll;
        for(int i=0; y; i++)
        {
            if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
            cur = cur*cur%P;
        }
        return ret;
    }
     
    void updsum(llong &x,llong y) {x = (x+y)%P;}
     
    int main()
    {
        fact[0] = 1ll; for(int i=1; i<=N*3; i++) fact[i] = fact[i-1]*i%P;
        finv[N*3] = quickpow(fact[N*3],P-2); for(int i=N*3-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
        scanf("%d",&n);
        for(int i=0; i<=2; i++) scanf("%s",a[i]+1);
        if(a[0][1]=='x'||a[0][n]=='x'||a[2][1]=='x'||a[2][n]=='x') {puts("0"); return 0;}
        for(int i=2; i<=n; i++) {if((a[0][i]=='x'&&a[0][i-1]=='x')||(a[2][i]=='x'&&a[2][i-1]=='x')) {puts("0"); return 0;}}
        int sum = a[1][1]=='x'?1:0;
        dp[1][sum][0] = 1ll;
        for(int i=2; i<=n; i++)
        {
            for(int j=1; j<=sum; j++) {updsum(dp[i-1][j][0],dp[i-1][j-1][0]),updsum(dp[i-1][j][1],dp[i-1][j-1][1]);}
            int now = (a[0][i]=='x')+(a[2][i]=='x'); sum += now+(a[1][i]=='x');
            if(a[1][i]=='o')
            {
                dp[i][0][0] = (dp[i-1][sum-now][0]+dp[i-1][sum-now][1])*fact[sum]%P*finv[sum-now]%P;
                continue;
            }
            for(int j=1; j<=sum; j++)
            {
                if(j-now-1>=0)
                {
                    updsum(dp[i][j][0],(dp[i-1][sum-now-1][1]-dp[i-1][j-now-1][1]+dp[i-1][sum-now-1][0]+P)*fact[j-1]%P*finv[j-now-1]%P);
                }
                if(now>=1)
                {
                    updsum(dp[i][j][1],dp[i-1][min(j-1,sum-now-1)][0]*fact[sum-j]%P*finv[sum-j-now]);
                    if(now==2&&j>=2) {updsum(dp[i][j][1],dp[i-1][j-2][0]*(sum-j)%P*(j-1)*2ll%P);}
                }
    //          printf("dp[%d][%d]=(%lld,%lld)
    ",i,j,dp[i][j][0],dp[i][j][1]);
            }
        }
        llong ans = 0ll;
        for(int i=0; i<=sum; i++) ans = (ans+dp[n][i][0])%P;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    k8s podpreset 参数注入
    python pipenv 包管理
    使用火狐浏览器访问双向认证的k8s api
    k8s api
    常用的排序算法的时间复杂度和空间复杂度
    flask 启动
    Redis系列-第四篇持久化与事务
    Redis系列-第五篇分布式锁与主从复制
    Redis系列-第六篇哨兵模式
    Docker系列-第一篇Docker简介
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11746667.html
Copyright © 2020-2023  润新知