• Codeforces 1045H Self-exploration 思维


    Self-exploration

    对于给定的c00, c01, c10, c11, 我们能得出0的段数, 1的段数, 0的个数, 1的个数。

    然后就是用隔板法算方案数, 对于小于A这个操作, 我们枚举小于的位置用同样的方法算方案数就好啦。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = (int)1e5 + 7;
    const int mod = (int)1e9 + 7;
    
    int inv[N], F[N], Finv[N], c[2][2], cc[2][2];
    int n, len;
    char s[N], t[N];
    
    
    inline int C(int n, int m) {
        if(n == -1 && m == -1) return 1;
        if(n < 0 || n < m) return 0;
        return 1LL * F[n] * Finv[m] % mod * Finv[n - m] % mod;
    }
    
    inline int getAns0(int c[2][2], int n) {
        if(c[0][1] < c[1][0] || c[0][1] > c[1][0] + 1) return 0;
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                if(c[i][j] < 0) return 0;
            }
        }
        int seg0, seg1;
        if(c[0][1] == c[1][0]) seg0 = c[0][1] + 1, seg1 = c[0][1];
        else seg0 = c[0][1], seg1 = c[0][1];
        int cnt0 = c[0][0] + seg0;
        int cnt1 = c[1][1] + seg1;
        if(cnt0 + cnt1 != n) return 0;
        return 1LL * C(cnt0 - 1, seg0 - 1) * C(cnt1 - 1, seg1 - 1) % mod;
    }
    
    inline int getAns1(int c[2][2], int n) {
        if(c[1][0] < c[0][1] || c[1][0] > c[0][1] + 1) return 0;
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                if(c[i][j] < 0) return 0;
            }
        }
        int seg0, seg1;
        if(c[1][0] == c[0][1]) seg1 = c[1][0] + 1, seg0 = c[1][0];
        else seg1 = c[1][0], seg0 = c[1][0];
        int cnt0 = c[0][0] + seg0;
        int cnt1 = c[1][1] + seg1;
        if(cnt0 + cnt1 != n) return 0;
        return 1LL * C(cnt0 - 1, seg0 - 1) * C(cnt1 - 1, seg1 - 1) % mod;
    }
    
    int solve(char *s, int n) {
        int ans = 0;
        memcpy(cc, c, sizeof(cc));
        for(int i = 2; i <= n; i++) {
            if(s[i] == '1') {
                cc[s[i - 1] - '0'][0]--;
                ans += getAns0(cc, n - i + 1);
                if(ans >= mod) ans -= mod;
                cc[s[i - 1] - '0'][0]++;
            }
            cc[s[i - 1] - '0'][s[i] - '0']--;
            if(cc[s[i - 1] - '0'][s[i] - '0'] < 0) return ans;
        }
        int ok = 1;
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                if(cc[i][j]) ok = 0;
            }
        }
        ans = (ans + ok) % mod;
        return ans;
    }
    
    int check(char *s, int n) {
        memset(cc, 0, sizeof(cc));
        for(int i = 1; i < n; i++) cc[s[i] - '0'][s[i + 1] - '0']++;
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                if(cc[i][j] != c[i][j]) return 0;
            }
        }
        return 1;
    }
    
    int main() {
        inv[1] = F[0] = Finv[0] = 1;
        for(int i = 2; i < N; i++) inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
        for(int i = 1; i < N; i++) F[i] = 1LL * F[i - 1] * i % mod;
        for(int i = 1; i < N; i++) Finv[i] = 1LL * Finv[i - 1] * inv[i] % mod;
        scanf("%s%s", s + 1, t + 1);
        int len_s = strlen(s + 1);
        int len_t = strlen(t + 1);
        scanf("%d%d%d%d", &c[0][0], &c[0][1], &c[1][0], &c[1][1]);
        len = 1;
        while(!getAns1(c, len) && len <= len_t) len++;
        if(len > len_t) return puts("0"), 0;
        int ans = 0;
        if(len_s < len && len < len_t) ans = getAns1(c, len);
        else if(len < len_s || len > len_t) ans = 0;
        else if(len == len_s && len == len_t) {
            ans = solve(t, len_t);
            ans -= solve(s, len_s) - check(s, len_s);
            if(ans < 0) ans += mod;
            if(ans >= mod) ans -= mod;
        }
        else if(len == len_s) {
            ans = getAns1(c, len);
            ans -= solve(s, len_s) - check(s, len_s);
            if(ans < 0) ans += mod;
        }
        else if(len == len_t) {
            ans = solve(t, len_t);
        }
        else assert(0);
        printf("%d
    ", ans);
        return 0;
    }
    
    /**
    **/
  • 相关阅读:
    从数据到代码—通过代码生成机制实现强类型编程
    .NET中oledb访问access含子查询的语句的参数置换顺序
    Android开发入门学习
    Shell脚本初步学习鸟哥Linux私房菜基础学习篇
    rpm打包学习
    关于计算机工作方向的几点想法
    source insight中文注释乱码问题的解决方案
    makefilerpm编译软件,输出依赖软件包的编译顺序
    在android中资源文件夹中添加一个新的图片资源
    Linux批量替换某种类型文件中的字符串sed和grep命令使用
  • 原文地址:https://www.cnblogs.com/CJLHY/p/11725242.html
Copyright © 2020-2023  润新知