hdu 5279 YJC plays Minecraft——生成函数

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5279

令 n 个点的树的 EGF 是 g(x) ,则 \( g(x) = \sum\limits_{i=0}^{\infty} \frac{i^{i-2}}{i!} x^i \)

令 n 个点的森林的 EGF 是 f(x) ,则 \( f(x) = \sum\limits_{i=0}^{\infty} \frac{g(x)^i}{i!} = e^{g(x)} \)

这道题里,每个团调用 f(x) 的对应项系数,n 条边就给答案乘上 2n

但要减去所有团、团之间的边构成一个环的情况。所以考虑 n 个点、1号点与 n 号点在同一棵树里的森林个数的 EGF h(x) 。

有这样的递推式: \( h[n]=\sum\limits_{i=1}^{n-1} g[n-i]*f[i]*\binom{n-2}{i-1} \) ,就是考虑与 1 号点在同一棵树里有 (n-i) 个点。

即 \( \frac{h[n]}{(n-2)!} = \sum\limits_{i=1}^{n-1} \frac{g[n-i]}{(n-i-1)!} * \frac{f[i]}{(i-1)!} \)

到这里,自己本来想的是后面的就是 \( x*f‘(x) \) 和 \( x*g‘(x) \) ,然后卷积。不过看看题解,发现前面是 h(x) 的二阶导,后面是 f(x) 和 g(x) 的一阶导。

那么 \( h(x) = \int \int f‘(x)*g‘(x) dx dx \)

注意数组长度是 219 而不是 218 ,因为倍增的 %t 的 t 可能是 218 ,此时的 len 应该是 219

注意预处理逆元要到 219 ,而不是和 jc[ ] ,jcn[ ] 一样只是 105

注意积分的时候要倒序遍历,以防 a[ ] 和 b[ ] 是同一个数组。

注意 get_exp( ) 的时候,本层的 len 要在 get_inv( ) 之后再赋值。并注意 \( 1-ln(f_0(x))+a(x) \) 的那个 1 是常数项,不是每项都有一个+1。

注意 \( i^{i-2} \) 里的 i 不能是 1 。

注意最后算 h(x) 的时候做积分,随便找了两个数组存积分结果,在乘起来之前要先把无关的项清空!!!

注意最后乘上 \( i! \) 才是真正的系数。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)fx=0;ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘)ret=ret*10+ch-‘0‘,ch=getchar();
  return fx?ret:-ret;
}
const int N=(1<<19)+5,mod=998244353;//1<<19 not 18 for t=2^18
int upt(int x){while(x>=mod)x-=mod;while(x<0)x+=mod;return x;}
int pw(int x,int k)
{int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;}

int n,ct[N],f[N],g[N],h[N],jc[N],jcn[N],bin[N];
int la[N],ia[N],tp[N],A[N],len,r[N],inv[N],wn[N],wn2[N];
void ntt_pre(int len)
{
  for(int R=2;R<=len;R++)
    {
      wn[R]=pw(3,(mod-1)/R);
      wn2[R]=pw(3,(mod-1)-(mod-1)/R);
    }
  inv[1]=1;
  for(int i=2;i<=len;i++)/////here not in init()
    inv[i]=(ll)upt(-mod/i)*inv[mod%i]%mod;
}
void ntt_len()
{
  for(int i=0,j=len>>1;i<len;i++)
    r[i]=(r[i>>1]>>1)+((i&1)?j:0);
}
void ntt(int *a,bool fx)
{
  for(int i=0;i<len;i++)
    if(i<r[i])swap(a[i],a[r[i]]);
  for(int R=2;R<=len;R<<=1)
    {
      int Wn=fx?wn2[R]:wn[R];
      for(int i=0,m=R>>1;i<len;i+=R)
    for(int j=0,w=1;j<m;j++,w=(ll)w*Wn%mod)
      {
        int x=a[i+j],y=(ll)w*a[i+m+j]%mod;
        a[i+j]=upt(x+y); a[i+m+j]=upt(x-y);
      }
    }
  if(!fx)return; int iv=inv[len];
  for(int i=0;i<len;i++)a[i]=(ll)a[i]*iv%mod;
}
void get_dao(int n,int *a,int *b)
{
  for(int i=0;i<n;i++)b[i]=(ll)(i+1)*a[i+1]%mod;
  b[n]=0;
}
void get_jf(int n,int *a,int *b)
{
  for(int i=n;i;i--)b[i]=(ll)inv[i]*a[i-1]%mod;//
  b[0]=0;
}
void get_inv(int n,int *a,int *b)
{
  b[0]=pw(a[0],mod-2);
  for(int t=2,yt=1,i,j;yt<n;yt=t,t=len)
    {
      len=t<<1; ntt_len();
      for(i=0;i<t;i++)tp[i]=a[i];
      for(;i<len;i++)tp[i]=0; for(i=yt;i<len;i++)b[i]=0;
      //b[i]=0 here for other get_inv pollute b[]//<len or t?
      ntt(tp,0); ntt(b,0);
      for(i=0;i<len;i++)b[i]=upt((ll)b[i]*(2-(ll)b[i]*tp[i]%mod)%mod);
      ntt(b,1);
    }
  for(int i=n;i<len;i++)b[i]=0;
}
void get_ln(int n,int *a,int *b)
{
  for(int i=0;i<n;i++)ia[i]=0;
  get_dao(n,a,b); get_inv(n,a,ia);
  len=n<<1; ntt_len();//len=n<<1 is ok
  ntt(b,0); ntt(ia,0);
  for(int i=0;i<len;i++)b[i]=(ll)b[i]*ia[i]%mod;
  ntt(b,1); for(int i=n;i<len;i++)b[i]=0;
  get_jf(n-1,b,b);
}
void get_exp(int n,int *a,int *b)
{
  b[0]=1;
  for(int t=2,yt=1,i,j;yt<n;yt=t,t=len)
    {
      for(i=yt;i<t;i++)b[i]=0; get_ln(t,b,la);//b[i]=0 before
      for(i=0;i<t;i++)la[i]=upt(-la[i]+a[i]);
      la[0]=upt(la[0]+1);/////not la[i]=1-la[i]+a[i]!!!
      len=t<<1; ntt_len();//////after get_ln!!!!!
      ntt(la,0); ntt(b,0);
      for(i=0;i<len;i++)b[i]=(ll)la[i]*b[i]%mod;
      ntt(b,1);
    }
  for(int i=n;i<len;i++)b[i]=0;
}
void init()
{
  n=1e5; for(len=1;len<=n;len<<=1);//len=mx_t
  ntt_pre(len<<1);
  jc[0]=1;for(int i=1;i<=n;i++)jc[i]=(ll)jc[i-1]*i%mod;
  jcn[n]=pw(jc[n],mod-2);
  for(int i=n-1;i>=0;i--)jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
  bin[0]=1;for(int i=1;i<=n;i++)bin[i]=upt(bin[i-1]<<1);

  g[1]=1;
  for(int i=2;i<=n;i++)//i=2 not i=1!!
    g[i]=(ll)pw(i,i-2)*jcn[i]%mod;
  get_exp(n+1,g,f);
  get_dao(n,g,ia); get_dao(n,f,la);
  for(len=1;len<n<<1;len<<=1); ntt_len();
  for(int i=n;i<len;i++)ia[i]=la[i]=0;//////!!!!!
  ntt(ia,0); ntt(la,0);
  for(int i=0;i<len;i++)ia[i]=(ll)ia[i]*la[i]%mod;
  ntt(ia,1);
  get_jf(n,ia,h); get_jf(n,h,h);
  for(int i=1;i<=n;i++)///
    {
      f[i]=(ll)f[i]*jc[i]%mod;
      g[i]=(ll)g[i]*jc[i]%mod;
      h[i]=(ll)h[i]*jc[i]%mod;
    }
}
int main()
{
  int T=rdn(); init();
  while(T--)
    {
      n=rdn();
      for(int i=1;i<=n;i++)ct[i]=rdn();
      int m1=bin[n],m2=1;
      for(int i=1;i<=n;i++) m1=(ll)m1*f[ct[i]]%mod;
      for(int i=1;i<=n;i++) m2=(ll)m2*upt(f[ct[i]]-h[ct[i]])%mod;
      printf("%d\n",upt(m1-m2));
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/10829343.html

时间: 2024-10-08 19:55:44

hdu 5279 YJC plays Minecraft——生成函数的相关文章

HDU 5279 YJC plays Minecraft (分治NTT优化DP)

题目传送门 题目大意:有$n$个小岛,每个小岛上有$a_{i}$个城市,同一个小岛上的城市互相连接形成一个完全图,第$i$个小岛的第$a_{i}$个城市和第$i+1$个小岛的第$1$个城市连接,特别地,第$n$个小岛的第$a_{n}$个城市和第$1$个小岛的第$1$个城市连接.现在要断掉图中的一些边,保证任意两个城市只有一条路径或者不连通,求合法的断边方案总数,$n,a_{i}<=1e5$ 完全不会(喷血 我们对每个小岛单独讨论 如果任意两个城市只有一条路径或者不连通,那么这张图只能是一个森林

hdu 5278 YJC plays automaton

YJC plays automaton Accepts: 1 Submissions: 14 Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 524288/262144 K (Java/Others) 问题描述 YJC是个小火车老司机,所以他是袜子坊烧饼栏目举办的"吃的更圆"竞赛金牌获得者,他去吃特色菜时看到一个n+1个状态的自动机,编号为0到n,其中0号点表示NULL,他非常好奇于是开始了研究: 他选取了一个初始状态集合S,

hdu 5277 YJC counts stars

hdu 5277 YJC counts stars 题意: 给出一个平面图,n个点,m条边,直线边与直线边之间不相交,求最大团的数目. 限制: 1 <= n <= 1000 思路: 因为平面图,直线边与直线边之间不相交,所以最大团的大小最大为4,m<=3*n-6. 所以对于答案4,枚举两条边. 对于答案3,枚举一条边一个点. /*hdu 5277 题意: 给出一个平面图,n个点,m条边.直线边与直线边之间不相交,求最大团的数目. 限制: 1 <= n <= 1000 思路:

hdu 5463 Clarke and minecraft

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5463 Clarke and minecraft Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 366    Accepted Submission(s): 193 Problem Description Clarke is a patien

hdu 5276 YJC tricks time 数学

YJC tricks time Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5276 Description YJC收到了一份神秘礼物.是一个长成这样的钟. YJC不是时间领主所以他并不能乱搞时间,但是这个钟实在是太难认了!所以他想来耍耍你. 现在YJC给你时针和分针间的夹角,让你告诉他现在是什么时候. 你将以以下格式给出可能的时间:HH:MM:SS分别表示小时,分钟

hdu 5277 YJC counts stars 暴力

YJC counts stars Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5277 Description YJC是个老火车小司机.一个晚上,他仰望天空,星辰璀璨,他突然觉得,天空就像一个平面,而每一个星辰,就是平面中的一个点.他把这些点编号为1到n.这些点满足任意三点不共线.他把一些点用线段连起来了,但是任意两条线段不会在端点以外相交.如果一个点的集合中任意两个

hdu 1521 排列组合 —— 指数型生成函数

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1521 标准的指数型生成函数: WA了好几遍,原来是多组数据啊囧: 注意精度,直接强制转换(int)是舍去小数,会WA,+0.5再强制转换或输出 %.0lf 是四舍五入,能A. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace

hdu 1398 Square Coins(生成函数,完全背包)

pid=1398">链接:hdu 1398 题意:有17种货币,面额分别为i*i(1<=i<=17),都为无限张. 给定一个值n(n<=300),求用上述货币能使价值总和为n的方案数 分析:这题能够用母函数的思想,对300以内的值进行预处理就可以 也可用全然背包思想求300以内的方案数 母函数: #include<stdio.h> int main() { int c1[305],c2[305],i,j,k,n; for(i=0;i<=300;i++){

hdu 5463 Clarke and minecraft(贪心)

Problem Description Clarke is a patient with multiple personality disorder. One day, Clarke turned into a game player of minecraft. On that day, Clarke set up local network and chose create mode for sharing his achievements with others. Unfortunately