【HDU 6397】Character Encoding 【生成函数公式推导】

In computer science, a character is a letter, a digit, a punctuation mark or some other similar symbol. Since computers can only process numbers, number codes are used to represent characters, which is known as character encoding. A character encoding system establishes a bijection between the elements of an alphabet of a certain size n and integers from 0 to n−1. Some well known character encoding systems include American Standard Code for Information Interchange (ASCII), which has an alphabet size 128, and the extended ASCII, which has an alphabet size 256.

For example, in ASCII encoding system, the word wdy is encoded as [119, 100, 121], while jsw is encoded as [106, 115, 119]. It can be noticed that both 119+100+121=340 and 106+115+119=340, thus the sum of the encoded numbers of the two words are equal. In fact, there are in all 903 such words of length 3 in an encoding system of alphabet size 128 (in this example, ASCII). The problem is as follows: given an encoding system of alphabet size n where each character is encoded as a number between 0 and n−1 inclusive, how many different words of length m are there, such that the sum of the encoded numbers of all characters is equal to k?

Since the answer may be large, you only need to output it modulo 998244353.
The first line of input is a single integer T (1≤T≤400), the number of test cases.

Each test case includes a line of three integers n,m,k (1≤n,m≤105,0≤k≤105), denoting the size of the alphabet of the encoding system, the length of the word, and the required sum of the encoded numbers of all characters, respectively.

It is guaranteed that the sum of n, the sum of m and the sum of k don’t exceed 5×106, respectively.
Output
For each test case, display the answer modulo 998244353 in a single line.

Sample Input
4
2 3 3
2 3 4
3 3 3
128 3 340

Sample Output
1
0
7
903

Source
2018 Multi-University Training Contest 8

百度了好多分析都是 公式推导都是一笔带过,我这菜鸡完全看不懂,只能求教考研的学长,非常感谢萌神帮我推了一些公式. 下面我详细的推导一下:
分析:我们可以构造多项式(生成函数)来求解 :

g(x)=(1+x1+x2+x3+...+xn1) g ( x ) = ( 1 + x 1 + x 2 + x 3 + . . . + x n − 1 )

那么 g(x)m g ( x ) m xk x k 的系数就是我们想求的答案:
g(x)m=(1+x1+x2+x3+...+xn1)m g ( x ) m = ( 1 + x 1 + x 2 + x 3 + . . . + x n − 1 ) m

首先分子分母都乘 (1x)m ( 1 − x ) m (乘 (1+x)m ( 1 + x ) m 也是可以的):
g(x)=(1x)m(1+x1+x2+x3+...+xn1)m(1x)m g ( x ) = ( 1 − x ) m ∗ ( 1 + x 1 + x 2 + x 3 + . . . + x n − 1 ) m ( 1 − x ) m

分子可以化简为 (1xn)m ( 1 − x n ) m
g(x)m=(1xn)m(1x)m g ( x ) m = ( 1 − x n ) m ( 1 − x ) m

分子可以用二项式定理展开:
(1xn)m=i=0m(1)ixni ( 1 − x n ) m = ∑ i = 0 m ( − 1 ) i ∗ x n ∗ i

首先把分母提到分子上,令 f(x)=(1x)m f ( x ) = ( 1 − x ) − m
f(x) f ( x ) 需要用到泰勒公式展开,首先要知道泰勒公式:
f(x)=f(a)+f(a)1!(xa)+f′′(a)2!(xa)2...fn(a)n!(xa)n+Rn(x) f ( x ) = f ( a ) + f ′ ( a ) 1 ! ∗ ( x − a ) + f ″ ( a ) 2 ! ∗ ( x − a ) 2 . . . f n ( a ) n ! ∗ ( x − a ) n + R n ( x )

这里我们将a赋值为0,其实赋值什么都可以,不过就是精度不同罢啦,有的可能要取更多的项才可以逼近,取为0的话会减少更多的项,从而简化我们的式子.
然后我们需要求出 y(x)=(1x)m y ( x ) = ( 1 − x ) − m 的泰勒展开,所以要先求出 y(x) y ( x ) 的一阶导,二阶导等等…,
y1(x)=m(1x)m1 y 1 ( x ) = m ∗ ( 1 − x ) − m − 1
y2(x)=m(m+1)(1x)m2 y 2 ( x ) = m ∗ ( m + 1 ) ∗ ( 1 − x ) − m − 2
yn(x)=m(m+1)(m+2)(m+3)...(m+n1)(1x)mn y n ( x ) = m ∗ ( m + 1 ) ∗ ( m + 2 ) ∗ ( m + 3 ) . . . ∗ ( m + n − 1 ) ∗ ( 1 − x ) − m − n

然后带入泰勒公式中,
f(x)=1+mx+m(m+1)2!x2...+(m+n1)!(m1)!n!xn... f ( x ) = 1 + m ∗ x + m ∗ ( m + 1 ) 2 ! ∗ x 2 . . . + ( m + n − 1 ) ! ( m − 1 ) ! ∗ n ! ∗ x n . . .

再化简成组合数的形式:
f(x)=i=0(i+m1m1)xi f ( x ) = ∑ i = 0 ∞ ( i + m − 1 m − 1 ) ∗ x i

这样分母就化简完啦.之后将分子和分母合并:
g(x)=i=0mj=0(1)i(j+m1m1)(mi)xni+j g ( x ) = ∑ i = 0 m ∑ j = 0 ∞ ( − 1 ) i ∗ ( j + m − 1 m − 1 ) ∗ ( m i ) ∗ x n ∗ i + j

之后我们枚举 i i , 那么j=kni, 然后就ok啦, 组合数的话提前预处理可以做到o(1).
ps:如果公式推导有问题,欢迎指出 。
代码

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <list>
#include <string>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;

const int N = (int) 1e6;
const int M = (int) 1e6 + 11;
const int MOD = (int) 998244353;
const double EPS = (double) 1e-9;
const double PI = (double)acos(-1.0);
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;

void read(int &x){
    char ch = getchar(); x = 0;
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
}
/*-----------------------------------------------------------------------------------*/ 

int Pow(int a, int b, int c = MOD){
    int s = 1; a %= c;
    while(b){
        if(b & 1) s = s * 1ll * a % c;
        b >>= 1;
        a = a * 1ll * a % c;
    }
    return s;
}
int fac[N], inv[N];
int C(int n, int m){
    if(n < m) return 0;
    return fac[n] * 1ll * inv[n - m] % MOD * inv[m] % MOD;
}
void init(){
    fac[0] = 1;
    for(int i = 1; i < N; i++) fac[i] = i * 1ll * fac[i - 1] % MOD;
    inv[N - 1] = Pow(fac[N - 1], MOD - 2); inv[0] = 1;
    for(int i = N - 2; i > 0; i--) inv[i] = inv[i + 1] * 1ll * (i + 1) % MOD;  
}
int main(){
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    init();
    int T; scanf("%d", &T);
    while(T--){
        int n, m, k; scanf("%d%d%d", &n, &m, &k);
        ll ans = 0;
        rep(i, 0, k / n + 1) {
            int j = k - n * i;
            if(!(i & 1)) ans += C(m + j - 1, m - 1) * 1ll * C(m, i) % MOD;
            else ans -= C(m + j - 1, m - 1) * 1ll * C(m, i) % MOD;
            ans = (ans + MOD) % MOD;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值