@description@

已知一个数(允许前导零)有 n 位(n 为偶数),并知道组成这个数的数字集合(并不一定要把集合内的数用完)。求有多少种可能,使得这个数前半部分的数位和等于后半部分的数位和。

模 998244353。

input

第一行两个整数:n k。表示这个数的位数以及组成这个数的数字集合大小。2 <= n <= 2*10^5,1 <= k <= 10。

第二行 k 个两两不同的整数 d1,d2,...,dk,表示组成这个数的数字集合。0 <= di <= 9。

output

输出可能数,模 998244353。

sample input

4 2

1 8

sample output

6

sample explain

6 种可能分别是:1111,1818,8118,1881,8181,8888。

@solution@

模数暗示 NTT。

如果长度为 n/2,数位和为 s 的数有 k 种,则它对答案的贡献为 \(k^2\)。

问题等价于求,长度为 n/2,数位和为 0,1,2,... 的数有多少种。

我们于是可以 dp。定义状态 \(dp[i][j]\) 表示长度为 i 的数,数位和为 j 的方案数。

定义 \(f\),使得 \(f[d[i]]=1(1\le i \le k)\)。可以得到状态转移方程:

\[dp[i][j] = \sum_{k=0}^{9}dp[i-1][j-k]*f[k]
\]

嗯好的这是一个卷积形式的 dp,我们可以用 NTT 来优化。

可以得到 \(dp[\frac{n}{2}][j] = f^{\frac{n}{2}}[j]\)。

转换成点值形式后直接快速幂再转换回来。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int G = 3;
const int MOD = 998244353;
const int MAXN = 200000*9*2;
int pow_mod(int b, int p) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%MOD;
b = 1LL*b*b%MOD;
p >>= 1;
}
return ret;
}
void ntt(int A[], int n, int type) {
for(int i=0,j=0;i<n;i++) {
if( i < j ) swap(A[i], A[j]);
for(int l=(n>>1);(j^=l)<l;l>>=1);
}
for(int s=2;s<=n;s<<=1) {
int t = (s >> 1);
int u = (type == 1) ? (pow_mod(G, (MOD-1)/s)) : (pow_mod(G, (MOD-1)-(MOD-1)/s));
for(int i=0;i<n;i+=s) {
for(int p=1,j=0;j<t;j++,p=1LL*p*u%MOD) {
int x = A[i+j], y = 1LL*A[i+j+t]*p%MOD;
A[i+j] = (x + y)%MOD, A[i+j+t] = (x + MOD - y)%MOD;
}
}
}
if( type == -1 ) {
int inv = pow_mod(n, MOD-2);
for(int i=0;i<n;i++)
A[i] = 1LL*A[i]*inv%MOD;
}
}
int f[MAXN + 5];
int main() {
int n, k, d, mx = 0;
scanf("%d%d", &n, &k);
for(int i=1;i<=k;i++) {
scanf("%d", &d);
mx = max(mx, d);
f[d] = 1;
}
int len; for(len = 1;len <= ((n>>1)*mx);len<<=1);
ntt(f, len, 1);
for(int i=0;i<len;i++)
f[i] = pow_mod(f[i], (n>>1));
ntt(f, len, -1);
int ans = 0;
for(int i=0;i<len;i++)
ans = (ans + 1LL*f[i]*f[i]%MOD)%MOD;
printf("%d\n", ans);
}

@details@

连续做了几天多项式毒瘤算法,做一个卷积优化是真的轻松惬意。

我才不会说因为 mx 没有弄初值 RE 了让我懵逼了好久。

我怎么可能会因为傻逼错误做不出来傻逼题。

@codeforces - 1096G@ Lucky Tickets的更多相关文章

  1. 2019.01.26 codeforces 1096G. Lucky Tickets(生成函数)

    传送门 题意简述:现在有一些号码由000~999中的某些数字组成(会给出),号码总长度为nnn,问有多少个号码满足前n2\frac n22n​个数码的和等于后n2\frac n22n​个数码的和(保证 ...

  2. Codeforces 1096G. Lucky Tickets【生成函数】

    LINK 题目大意 很简单自己看 思路 考虑生成函数(为啥tags里面有一个dp啊) 显然,每一个指数上是否有系数是由数集中是否有这个数决定的 有的话就是1没有就是0 然后求出这个生成函数的\(\fr ...

  3. Codeforces - 1096G - Lucky Tickets - NTT

    https://codeforc.es/contest/1096/problem/G 把数组分成前后两半,那么前半部分的各个值的表示方案的平方的和就是答案. 这些数组好像可以dp出来. 一开始设dp[ ...

  4. Codeforces Gym 100418J Lucky tickets 数位DP

    Lucky ticketsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view ...

  5. POJ-2346 Lucky tickets(线性DP)

    Lucky tickets Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3298 Accepted: 2174 Descrip ...

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

    All bus tickets in Berland have their numbers. A number consists of n digits (n is even). Only k dec ...

  7. DP+高精度 URAL 1036 Lucky Tickets

    题目传送门 /* 题意:转换就是求n位数字,总和为s/2的方案数 DP+高精度:状态转移方程:dp[cur^1][k+j] = dp[cur^1][k+j] + dp[cur][k]; 高精度直接拿J ...

  8. Ural 1036 Lucky Tickets

    Lucky Tickets Time Limit: 2000ms Memory Limit: 16384KB This problem will be judged on Ural. Original ...

  9. POJ 2346:Lucky tickets

    Lucky tickets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3247   Accepted: 2136 Des ...

随机推荐

  1. ES6 新的数据类型Map和Set

    Map Map是一组键值对的结构,具有极快的查找速度. 举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array: var names = ['Michael', 'Bo ...

  2. nslookup查不到数据

    ch查不到数据 换一个ip就可以了,什么原理?

  3. Linux下允许MySQL 授权远程连接

    1.mysql -u root -p   (root)用户名 2.mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'r ...

  4. GDOI2017第四轮day1总结

    总的来说这场比赛,只能说是勉强正常发挥. 实在是知识水平有限,最后没能突破瓶颈. 有几个做得好的地方: 1.想好了在写题: 2.暴力也会拍 3.适当地放弃题. 要学习的东西: 1.Sg,线性基: 2. ...

  5. win下在虚拟机安装CentOS 7 Linux系统

    准备: CentOS 7下载地址(我下的是everthing版本):https://www.centos.org/download/ 一.首先下载安装虚拟机VMware 地址官网下载即可. 二.安装操 ...

  6. 2-3 Numpy+Matplotlib可视化(一)

    (1)pyplot基础绘图 # -*-coding:utf-8-*- # !/usr/bin/env python # Author:@vilicute import numpy as np impo ...

  7. elipse egit的使用

  8. 调试R代码中出现的常用的函数

    1. 字符串连接函数 paste的一般使用格式为: paste(..., sep = " ", collapse = NULL) ...表示一个或多个R可以被转化为字符型的对象:s ...

  9. Effective Modern C++:07并发API

    C++11的志伟功勋之一,就是将并发融入了语言和库中,因此在C++的历史上,程序员可以首次跨越所有平台撰写具有标准行为的多线程程序. 35:优先选用基于任务而非基于线程的程序设计 如果需要以异步的方式 ...

  10. Sublime text2 常用插件

    很早就安装了这款软件,因为听说很NB.但是一直都是习惯用vim, 所以一直没有去学习它, 现在用用感觉确实很不错,所以找了些插件, 参考网址: http://www.hphq.net/Marketin ...