• CF1096. G. Lucky Tickets(快速幂NTT)


    All bus tickets in Berland have their numbers. A number consists of n digits (n is even). Only k decimal digits d1,d2,,dk can be used to form ticket numbers. If 0 is among these digits, then numbers may have leading zeroes. For example, if n=4 and only digits 0 and 4 can be used, then 0000, 4004, 4440 are valid ticket numbers, and 0002, 00, 44443

    are not.

    A ticket is lucky if the sum of first n/2

    digits is equal to the sum of remaining n/2

    digits.

    Calculate the number of different lucky tickets in Berland. Since the answer may be big, print it modulo 998244353

    .

    Input

    The first line contains two integers n

    and k (2n2105,1k10) — the number of digits in each ticket number, and the number of different decimal digits that may be used. n

    is even.

    The second line contains a sequence of pairwise distinct integers d1,d2,,dk

    (0di9)

    — the digits that may be used in ticket numbers. The digits are given in arbitrary order.

    Output

    Print the number of lucky ticket numbers, taken modulo 998244353

    .

    Examples
    Input
    Copy
    4 2
    1 8
    Output
    Copy
    6
    Input
    Copy
    20 1
    6
    Output
    Copy
    1
    Input
    Copy
    10 5
    6 1 4 0 3
    Output
    Copy
    569725
    Input
    Copy
    1000 7
    5 4 0 1 8 3 2
    Output
    Copy
    460571165
    Note

    In the first example there are 6

    lucky ticket numbers: 1111, 1818, 1881, 8118, 8181 and 8888

    .

    There is only one ticket number in the second example, it consists of 20

    digits 6. This ticket number is lucky, so the answer is 1.

    题意:给定你K种数可以选,问你有多少排列,使得前半部分的和等于后半部分的和。

    思路:我们枚举“和”的大小,令A[i]表示长度为N/2时和为i的方案数,那么答案就是所有的A[i]*A[i];

    怎么就Ai呢,就是一个多项式(P0.X0+P1*X1+...*P9*X9)^(N/2);p是0或者1;

    多项式的N次,我们可以用快速幂+FFT来加速,这里要取模,写的NTT。然后就是可以直接一次DFT+快速幂+IDFT。

    (之前纠结过为什么可以一次DFT就搞定了,而不是logN次,现在看来是对的,正确性我还需要学习一下。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    #define ll long long
    const int G=3;
    const int maxn=2148576;
    const int Mod=998244353;
    int mod,n,k,rev[maxn],lim,ilim,s,wn[maxn+1];
    std::vector<int> v;
    inline int pow(int x, int y) {
        int ans=1;
        for(;y;y>>=1,x=(ll)x*x%mod)
          if(y&1) ans=(ll)ans*x%mod;
        return ans;
    }
    inline int& up(int& x, int y) { if ((x+=y)>=mod) x-=mod; return x; }
    inline void NTT(int* A, int typ) {
        rep(i,0,lim-1) if (i<rev[i]) swap(A[i], A[rev[i]]);
        for (int i=1;i<lim;i+=i) {
            const int t=lim/i/2;
            for (int j=0;j<lim;j+=i+i) {
                for (int k=0;k<i; k++) {
                    int w=typ?wn[t*k]:wn[lim-t*k];
                    int x=A[k+j],y=(ll)w*A[k+j+i]%mod;
                    up(A[k+j],y),up(A[k+j+i]=x,mod-y);
                }
            }
        }
        if (!typ) rep(i,0,lim-1) A[i]=(ll)ilim*A[i]%mod;
    }
    inline void init(int len,int tmod) {
        mod=tmod; lim=1; s=-1;
        while(lim<len) lim+=lim,s++;  ilim=pow(lim,mod-2);
        rep(i,0,lim-1) rev[i]=rev[i>>1]>>1|(i&1)<<s;
        int w=pow(G,(mod-1)/len);
        wn[0]=1;
        rep(i,1,lim) wn[i]=(ll)(wn[i-1])*w%mod;
    }
    int A[maxn];
    int main() {
        scanf("%d%d",&k,&n); k/=2;
        int x,ans=0; rep(i,1,n) scanf("%d",&x), A[x]=B[x]=1;
        init(2097152, 998244353);
        NTT(A, 1);
        rep(i,0,lim-1) A[i]=pow(A[i],k);
        NTT(A, 0);
        rep(i,0,2000000) (ans+=(ll)A[i]*A[i]%Mod)%=Mod;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    浅谈FastJson的TypeReference用法
    勾选表中的行数据,点击添加,添加到另一个表中(二)
    获取表单内的所有元素的值 表单格式化插件jquery.serializeJSON
    基于BootStrap的Collapse折叠(包含回显展开折叠的对应状态)
    删除按钮和单条删除合并
    前台校验是否为空
    浅谈js的join()方法
    select前台转义后台取到的值为对应的文本 select同时接受list和map
    SpringBoot图片上传(二)
    给div拼接html 拼接字符串
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10194502.html
Copyright © 2020-2023  润新知