@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. 轮播图js版&jQ版

    JS版轮播图 html部分和css部分自己任意定 主要构成: 1,一个固定的框 超出框的部分隐藏 2,几张图片float:left 3,下部下原点,点击切换,切换到不同的张都有红色显示 4,左右两个大 ...

  2. Hdu 1150

    Machine Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  3. Node.js的框架-express

    Node.js的框架 express 是第三方的 express const express=require('express'); const app=express(); const PORT=3 ...

  4. layui的select联动 - CSDN博客

    要实现联动效果注意两点: 第一要可以监听到select的change事件: 第二异步加载的内容,需要重新渲染后才可以 正常使用. html结构: <form class="layui- ...

  5. 在Liferay 7中如何自定义一个Portlet的toolbar

    哈哈,懒得自己写了,直接贴教程了,你想为那个portlet添加自定义的toolbar,就在javax.portlet.name=属性中写上它的值.教程博客:Adding Portlet URL in ...

  6. Javascript一些要点记录

    1. == 比较,它会自动转换数据类型再比较 === 比较,它不会自动转换数据类型,如果数据类型不一致,返回false 大部分时候应该使用===来比较2. 使用'use strict'来强制通过var ...

  7. Intersection of Two Linked Lists两链表找重合节点

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  8. Spring_通过Bean的Factory配置Bean

    package com.tanlei.bean.FactoryBean; import org.springframework.beans.factory.FactoryBean; public cl ...

  9. springboot集成mongoDB 异常认证

    1.springboot连接mongoDB 出现异常认证 异常详情: com.mongodb.MongoSecurityException: Exception authenticating Mong ...

  10. 网络流24题 餐巾计划(DCOJ8008)

    题目描述 一个餐厅在相继的 n nn 天里,每天需用的餐巾数不尽相同.假设第 i ii 天需要 ri r_ir​i​​ 块餐巾.餐厅可以购买新的餐巾,每块餐巾的费用为 P PP 分:或者把旧餐巾送到快 ...