• B


    http://codeforces.com/gym/101161/attachments

    今天被卡常了,其实是自己对组合数技巧研究的不够。

    如果是n, m <= 1e5的,然后取模是质数,那么可以用费马小定理。

    如果n, m都比较小,那么其实是直接杨辉三角。不用逆元那些。

    这题的思路是,枚举每一一个ave,然后总和就是n * ave

    相当于方程  x1 + x2 + .... + xn = n * ave中,在0 <= x[i] <= full的情况下,不同解的个数中,使得x[i] == ave的个数。每有一个x[i] == ave

    ans++

    首先x1 + x2 + ..... + xn = n * ave在0 <= x[i] <= full有多少个不同的解,可以容斥出来,这里就不说了,复杂度O(n)

    可以看看这个,http://www.cnblogs.com/liuweimingcprogram/p/6091396.html

    然后怎么统计有多少个ans

    考虑每一个的贡献,因为每个人的贡献是独立的,

    如果x[1] == ave,有多少种情况?就是x2 + x3 + ..... + xn = ave * n - ave的合法解的个数种。

    x[2] == ave同理,所以ans += n * 合法总数。

    就比如ave = 1, 序列1、1、1中,贡献是3,其中x1 = 1的时候,x2 = x3 = 1一种,然后x2 = 1, x1 = x3 = 1又是一种。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <string>
    #include <stack>
    #include <map>
    #include <set>
    #include <bitset>
    #define X first
    #define Y second
    #define lson T[rt].l
    #define rson T[rt].r
    #define clr(u,v); memset(u,v,sizeof(u));
    #define in() freopen("data.txt","r",stdin);
    #define out() freopen("ans","w",stdout);
    #define Clear(Q); while (!Q.empty()) Q.pop();
    #define pb push_back
    
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pii;
    const int maxn = 1e6 + 20;
    LL C[14000 + 2][60 + 2];
    const int MOD = 1e9 + 7;
    LL calc(int n, int en, int sum) {
        if (sum < 0) return 0;
        LL all = C[sum + n - 1][n - 1];
        for (int i = 1; i <= n; ++i) {
            int fuck = sum - i * (en + 1) + n - 1;
            if (fuck < 0) break; //notice
            if (i & 1) {
                all = (all + MOD - C[n][i] * C[fuck][n - 1] % MOD) % MOD;
            } else all = (all + MOD + C[n][i] * C[fuck][n - 1] % MOD) % MOD;
        }
        return all;
    }
    int n, full;
    void work() {
        LL ans = 0;
        for (int i = 0; i <= full; ++i) { // 枚举ave
            ans += n * calc(n - 1, full, i * n - i) % MOD;
            ans %= MOD;
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        in();
    #else
    #endif
        C[0][0] = 1;
        C[1][0] = 1, C[1][1] = 1;
        for (int i = 2; i <= 14000; ++i) {
            int en = min(60, i);
            C[i][0] = 1;
            for (int j = 1; j <= en; ++j) {
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
            }
        }
        while (scanf("%d%d", &n, &full) > 0 && (n + full)) work();
        return 0;
    }
    View Code
  • 相关阅读:
    重读金典------高质量C编程指南(林锐)-------第四章 表达式和基本语句
    重读金典------高质量C编程指南(林锐)-------第三章 命名规则
    重读金典------高质量C编程指南(林锐)-------第二章 程序的板式
    重读金典------高质量C编程指南(林锐)-------第一章 文件结构
    链表的基本操作---创建
    实现两个数的互换算法小结
    C++中引用与指针的区别
    以前写的一些小程序总结
    OPENCV中数字图像处理知识运用
    常见的论文查找办法
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/7309139.html
Copyright © 2020-2023  润新知