洛谷P5162 WD与积木 [DP,NTT]
思路
真是非常套路的一道题……
考虑\(DP\):设\(f_n\)为\(n\)个积木能搭出的方案数,\(g_n\)为所有方案的高度之和。
容易得到转移方程:
&f_n=[n=0]+\sum_{i=1}^n {n \choose i} f_{n-i}\\
&g_n=\sum_{i=1}^n {n \choose i} (f_{n-i}+g_{n-i})
\end{align*}
\]
发现\(f_n\)似乎更容易搞出来,我们先搞\(f_n\)。
由转移方程可以得到:
\]
设
S(x)=\sum_{n=1}^{\infty} \frac{1}{n!} x^n
\]
则有
F(x)-1&=F(x)S(x)\\
F(x)&=\frac{1}{1-S(x)}
\end{align*}
\]
多项式求逆即可。
接下来是求\(g_n\)。
令\(t_n=f_n+g_n\),则有
\]
设
&G(x)=\sum_n \frac{g_n}{n!} x^n\\
&T(x)=\sum_n \frac{t_n}{n!}=F(x)+G(x)
\end{align*}
\]
可以得到
G(x)=\frac{S(x)F(x)}{1-S(x)}=S(x)[F(x)]^2=F(x)(F(x)-1)
\]
NTT即可。
最后\(ans_n=\frac{g_n}{f_n}\)。
代码
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 400404
typedef long long ll;
const ll mod=998244353;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.')
{
ch=getchar();
while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
inline ll ksm(ll x,int y)
{
ll ret=1;
for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
return ret;
}
ll inv(ll x){return ksm(x,mod-2);}
int r[sz],limit;
void NTT_init(int n)
{
limit=1;int l=-1;
while (limit<=n+n) limit<<=1,++l;
rep(i,0,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<l);
}
void NTT(ll *a,int type)
{
rep(i,0,limit-1) if (i<r[i]) swap(a[i],a[r[i]]);
for (int mid=1;mid<limit;mid<<=1)
{
ll Wn=ksm(3,(mod-1)/mid>>1);if (type==-1) Wn=inv(Wn);
for (int len=mid<<1,j=0;j<limit;j+=len)
{
ll w=1;
for (int k=0;k<mid;k++,w=w*Wn%mod)
{
ll x=a[j+k],y=w*a[j+k+mid]%mod;
a[j+k]=(x+y)%mod;a[j+k+mid]=(mod+x-y)%mod;
}
}
}
if (type==1) return;
ll I=inv(limit);
rep(i,0,limit-1) a[i]=a[i]*I%mod;
}
ll tmp1[sz],tmp2[sz];
void PolyInv(ll *a,ll *f,int n)
{
if (n==1) return (void)(f[0]=inv(a[0]));
int mid=(n+1)>>1;
PolyInv(a,f,mid);
NTT_init(n);
rep(i,0,mid-1) tmp1[i]=f[i];
rep(i,0,n-1) tmp2[i]=a[i];
NTT(tmp1,1);NTT(tmp2,1);
rep(i,0,limit-1) tmp1[i]=tmp1[i]*(mod+2-tmp1[i]*tmp2[i]%mod)%mod;
NTT(tmp1,-1);
rep(i,0,n-1) f[i]=tmp1[i];
rep(i,0,limit-1) tmp1[i]=tmp2[i]=0;
}
ll fac[sz],_fac[sz];
void init(){fac[0]=_fac[0]=1;rep(i,1,sz-1) _fac[i]=inv(fac[i]=fac[i-1]*i%mod);}
ll f[sz],g[sz],s[sz];
ll t1[sz],t2[sz],t3[sz],t4[sz];
int main()
{
file();
init();
int n=1e5+5,T;
rep(i,1,n) s[i]=mod-_fac[i];
++s[0];
PolyInv(s,t1,n);
rep(i,1,n) f[i]=t1[i];f[0]=1;
rep(i,0,n) t2[i]=t3[i]=f[i];--t3[0];
NTT_init(n);
NTT(t2,1);NTT(t3,1);
rep(i,0,limit-1) t4[i]=t2[i]*t3[i]%mod;
NTT(t4,-1);
rep(i,1,n) g[i]=t4[i];
read(T);
while (T--) read(n),printf("%lld\n",g[n]*inv(f[n])%mod);
}
洛谷P5162 WD与积木 [DP,NTT]的更多相关文章
- 洛谷 P5162 WD与积木 解题报告
P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...
- 洛谷 P5162 WD与积木【多项式求逆】
设f[i]为i个积木能堆出来的种类,g[i]为i个积木能堆出来的种类和 \[ f[n]=\sum_{i=1}^{n}C_{n}^{i}g[n-i] \] \[ g[n]=\sum_{i=1}^{n}C ...
- 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)
洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\).我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...
- 洛谷2344 奶牛抗议(DP+BIT+离散化)
洛谷2344 奶牛抗议 本题地址:http://www.luogu.org/problem/show?pid=2344 题目背景 Generic Cow Protests, 2011 Feb 题目描述 ...
- Lightning Conductor 洛谷P3515 决策单调性优化DP
遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...
- 洛谷P1541 乌龟棋(四维DP)
To 洛谷.1541 乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游 ...
- 【洛谷】P1052 过河【DP+路径压缩】
P1052 过河 题目描述 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上.由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙 ...
- 【题解】洛谷P1052 [NOIP2005TG] 过河(DP+离散化)
题目来源:洛谷P1052 思路 一开始觉得是贪心 但是仔细一想不对 是DP 再仔细一看数据不对 有点大 如果直接存下的话 显然会炸 那么就需要考虑离散化 因为一步最大跳10格 那么我们考虑从1到10都 ...
- 洛谷1736(二维dp+预处理)
洛谷1387的进阶版,但很像. 1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对 ...
随机推荐
- 【51nod 1191】消灭兔子
Description 有N只兔子,每只有一个血量B[i],需要用箭杀死免子.有M种不同类型的箭可以选择,每种箭对兔子的伤害值分别为D[i],价格为P[i](1 <= i <= M).假设 ...
- Discuz 论坛 (LAMP环境)
Discuz 论坛系统运行依赖 LAMP/LNMP的基础环境. 1.使用 yum 安装 MySQL: yum install mysql-server -y service mysqld restar ...
- [C++]2-5 分数化小数
/* 分数化小数 输入正整数a,b,c,输出a/b的小数形式.精确到小数点后C位.a,b<=10^6,c<=10^6. 输入包含多组数据,结束标记为a=b=c=0 样例输入: 1 6 4 ...
- JavaScript面试技巧(一):基础知识
1.变量类型和计算 变量类型:值类型.引用类型.typeof运算符. 变量计算:字符串拼接.==运算符.if语句.逻辑运算符 2.原型和原型链 构造函数 5个原型规则 3.作用域和闭包-执行上下文 4 ...
- 2017CCPC秦皇岛 M题Safest Buildings&&ZOJ3993【复杂模拟】
题意: 给出两个半径R,r,R表示第一次的大圈半径,r表示第二次的小圈半径.第一次大圈的圆心位于(0,0),第二次小圈的圆心未知,但在大圈内,给你一个n,然后给出n个屋子的位置,问这些屋子中,第二次在 ...
- Lattice
Lattice是一个无环WFSA,结点可以是hmm状态.hmm(音素).词,每个结点是一段音频在某个时间的对齐 用训练好的声学模型.现成的语言模型和发音字典构建解码网络(wfst),最后将提取的测试集 ...
- 帮助类-从tfs获取数据
using JC.Helper; using Microsoft.TeamFoundation.Client; using Microsoft.TeamFoundation.Framework.Cli ...
- Java基础 变量的作用域
变量的作用域: 1. Java用一对大括号作为语句块的范围,称为作用域. 2.作用域中的变量不能重复定义. 3.离开作用域,变量所分配的内存空间将被JVM回收. public void name(){ ...
- jQuery源码分析学习--资料收集--更新中
1.逐行分析jQuery源码的奥秘 - 网易云课堂 http://study.163.com/course/courseMain.htm?courseId=465001#/courseDetail? ...
- 多分类Logistics回归公式的梯度上升推导&极大似然证明sigmoid函数的由来
https://blog.csdn.net/zhy8623080/article/details/73188671 也即softmax公式