• 清北学堂模拟赛d4t6 c


    分析:这道题比较有难度.

          观察题目,发现只有当一行翻了奇数次后才会产生黑色格子,设有x行被翻了奇数次,y列被翻了偶数次,那么x*m + y*n - 2*x*y = s,接下来就要解方程了.对于二元一次方程,先枚举其中一个未知数x,就能推得y = (s - x*m)/(n - 2*x).假设翻了奇数次的x行y列各只用x,y次操作,那么接下来的任务就是把剩下的没用完的次数给分配出去,而且不能改变奇偶性.如果每一次操作是把一行或一列翻两次,那么就是要把(r - x)/2次操作分给n行,(c - y)/2次操作分给m列,这个的方案数可以用隔板法来求解,即:

    C((r - x) / 2 + n - 1,n - 1),C((c - y) / 2 + m - 1,m - 1),n行m列中选x行y列的方案数为C(n,x),

    C(m,y),那么答案就是C((r - x) / 2 + n - 1,n - 1)*C((c - y) / 2 + m - 1,m - 1)*C(n,x)*C(m,y).

          统计方案数的时候要看y是不是整数,并且r-x和c-y要能被2整除.最后要特判一种情况:x*2=n,在这种情况下,无论多少列被染了奇数次黑色格子永远是那么多,把所有列的情况算一次就好了.

    以后取模运算要单独开一个函数写,这样不容易错.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    const int mod = 1e9 + 7, maxn = 100010;
    
    using namespace std;
    long long p[maxn];
    int n, m, r, c;
    long long s, v1[maxn], v2[maxn], v3[maxn], v4[maxn], ans;
    
    long long mul(long long a, long long b)
    {
        a *= b;
        if (a >= mod)
            a %= mod;
        return a;
    }
    
    void inc(long long &a, long long b)
    {
        a += b;
        if (a >= mod)
            a -= mod;
    }
    
    long long qpow(long long a, long long b)
    {
        long long res = 1;
        while (b)
        {
            if (b & 1)
                res = mul(res, a);
            b >>= 1;
            a = mul(a, a);
        }
        return res;
    }
    
    int main()
    {
        scanf("%d%d%d%d%lld", &n, &m, &r, &c, &s);
        
        p[1] = 1;
        for (int i = 2; i <= 100000; i++) //逆元
            p[i] = ((mod - mod / i) * p[mod % i]) % mod;
            
        long long temp = 1;
        for (int i = 0; i <= r; i++)  //求C(n + i - 1,n - 1)
        {
            v1[i] = temp;
            temp = mul(temp, mul(i + n, p[i + 1]));
        }
        temp = 1;
        for (int i = 0; i <= c; i++)
        {
            v2[i] = temp;
            temp = mul(temp, mul(i + m, p[i + 1]));
        }
        temp = 1;
        for (int i = 0; i <= n; i++)
        {
            v3[i] = temp;
            temp = mul(temp, mul(n - i, p[i + 1]));
        }
        temp = 1;
        for (int i = 0; i <= m; i++)
        {
            v4[i] = temp;
            temp = mul(temp, mul(m - i, p[i + 1]));
        }
        for (long long i = r & 1; i <= min(n, r); i += 2)
        {
    
            if (i * 2 != n)
            {
                if (((s - (long long)m * i)) % (n - i * 2))
                    continue;
                long long b = (s - (long long)i * m) / (n - i * 2);
                if (b > c || b < 0 || (c - b) & 1)
                    continue;
                long long temp = v3[i];
                temp = mul(temp, v1[(r - i) >> 1]);
                temp = mul(temp, v4[b]);
                temp = mul(temp, v2[(c - b) >> 1]);
                inc(ans, temp);
            }
            else
            {
                if ((long long)i * m != s)
                    continue;
                long long temp = v3[i];
                temp = mul(temp, v1[(r - i) >> 1]);
                long long cnt = 0;
                for (int b = (c & 1); b <= min(r, c); b += 2)
                    inc(cnt, mul(v4[b], v2[(c - b) >> 1]));
                inc(ans, mul(temp, cnt));
            }
        }
        printf("%lld
    ", ans);
    
        return 0;
    }
  • 相关阅读:
    如何用最小的代价完成爬虫需求
    那些年我们一起守护的“密”
    自动化中间人攻击工具subterfuge小实验
    XP操作系统设置:[82]关机快捷键
    如何绕过Win8、Win10的systemsetting与注册表校验设置默认浏览器
    定时启动和关闭指定程序的方法
    Delphi 的内存操作函数(2): 给数组指针分配内存
    Delphi 的内存操作函数(1): 给字符指针分配内存
    Java Gearman Service
    分布式计算框架Gearman原理详解
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7645927.html
Copyright © 2020-2023  润新知