2018 Multi-University Training Contest 8--HDU 6397 Character Encoding(数论)

题意:

假设有 0 到 n-1种数字,随机选取(可以重复),得到的和为k组合数量有多少种。

题解:

设想一个 n 为3的情况:

m\k012345678
1111000000
2123210000
3136763100
414101619161031

设想一个 n 为4的情况:

m\k0123456789101112
11111000000000
21234321000000
313610121210631000
41410203140444031201041

我们可以发现这是一个展开式三角形  (1+x+x^2+x^3...+x^n-1)^m。

推导:

x1+x2+...+xm = k (xi 无上界) 想到了隔离板的问题:

7个球用3个隔离板分开的有多少情况,即 C(6,3);

所以设 Xi = xi+1,得:X1+X2+...+Xm = k + m ,所以在xi < n的情况下有 C(k+m-1,m-1) 种情况。

同理 x1+x2+...+xm = k (xi < n),则令 Xi = x1+1-n 得:X1+X2+...+Xm = k + m - c*n(c 为xi超过n的个数);

所以有C(k+m-c*n-1, m-1)种情况,但是c的个数和位置是不一样的,所以要乘以C(m,c)。

因为容斥,所以可以得到公式:

T(m,k) = \sum_{0}^{k/n} (-1)^i*C(m,i)*C(m+k-1-n*i,m-1)

比赛的时候很惨,疯狂WA,赛后发现在求和的过程中没有 +mod 导致答案会有出入,心好累。

AC代码:

#include <algorithm>
#include  <iostream>
#include   <cstdlib>
#include   <cstring>
#include    <cstdio>
#include    <string>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <cmath>
#include     <deque>
#include     <queue>
#include      <list>
#include       <set>
#include       <map>
#define mem(a) memset(a, 0, sizeof(a))
#define pi acos(-1)
using namespace std;
typedef long long ll;

const ll mod = 998244353;
const int maxn = 2e5+10;

ll fac[maxn], inv[maxn], ans[maxn];
ll temp;

ll getpow(ll a, int b){
    ll sum = 1;
    while(b){
        if(b & 1){
            sum = (sum * a) % mod;
        }
        a = (a*a) % mod;
        b >>= 1;
    }
    return sum;
}
 
ll C(int n, int m){
    return fac[n]*inv[m]%mod * inv[n-m]%mod;
}
 
void init(){
    temp = getpow(2, mod-2);
    fac[0] = inv[0] = 1;
    for(int i = 1; i < maxn; i++){
        fac[i] = (i*fac[i-1]) % mod;
        inv[i] = getpow(fac[i], mod-2);
    }
}

int main(){
    int t;
    init();
    scanf("%d", &t);
    while(t--){
        ll n, m, k;
        scanf("%lld %lld %lld", &n, &m, &k);
		ll sum = 0;
        for(ll r = 0; r <= k/n; r++){
            if(r%2){
                sum = (sum+mod-C(m, r)*C(k-n*r+m-1, m-1) % mod) % mod;
            }
            else{
                sum = (sum+mod+C(m, r)*C(k-n*r+m-1, m-1) % mod) % mod;
            }
        }
        printf("%lld\n", sum % mod);
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值