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$

完全不会(喷血

我们对每个小岛单独讨论

如果任意两个城市只有一条路径或者不连通,那么这张图只能是一个森林

定义$f[i]$表示$i$个点的完全图的答案

我们对第$i$个点所在的树进行讨论, 设$i$点所在的树除了$i$点还有$j$个节点,可以得到方程

$f[i]=\sum\limits_{j=0}^{i-1} C_{i-1}^{j}f[i-j-1](j+1)^{j-1}$

完全图有标号生成树个数是$n^{n-2}$

把上述式子展开,发现是一个卷积形式,可以用分治$NTT$求解

显然小岛间的边至少断一条就ok了

如果一条都不断边呢?

就要保证至少一个小岛内的$1$号点和$a_{i}$号点不连通

我们去掉每个小岛的$1$号点和$a_{i}$号点都连通的方案数就行了

这种情况的$DP$方程和上面的差不多, 设$i$点所在的树除了$i$点和$1$号点还有$j$个节点

$g[i]=\sum\limits_{j=0}^{i-2} C_{i-1}^{j-1}f[i-j-2](j+2)^{j}$

不用分治直接$NTT$就行了

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 (1<<18)+10
  6 #define il inline
  7 #define dd double
  8 #define ld long double
  9 #define ll long long
 10 using namespace std;
 11
 12 const int inf=0x3f3f3f3f;
 13 const ll p=998244353;
 14 int gint()
 15 {
 16     int ret=0,fh=1;char c=getchar();
 17     while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();}
 18     while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();}
 19     return ret*fh;
 20 }
 21 ll qpow(ll x,ll y)
 22 {
 23     ll ans=1;
 24     for(;y>0;x=x*x%p,y>>=1) if(y&1) ans=ans*x%p;
 25     return ans;
 26 }
 27
 28 int T,n,m;
 29 namespace NTT{
 30 ll a[N1],b[N1],c[N1],Wn[N1],_Wn[N1];
 31 int r[19][N1];
 32 void Pre(int len,int L)
 33 {
 34     int i,j;
 35     for(j=1;j<=L;j++) for(i=0;i<(1<<j);i++)
 36         r[j][i]=(r[j][i>>1]>>1)|((i&1)<<(j-1));
 37     for(i=1;i<=len;i<<=1) Wn[i]=qpow(3,(p-1)/i), _Wn[i]=qpow(Wn[i],p-2);
 38 }
 39 void NTT(ll *s,int len,int type,int L)
 40 {
 41     int i,j,k; ll wn,w,t;
 42     for(i=0;i<len;i++) if(i<r[L][i]) swap(s[i],s[r[L][i]]);
 43     for(k=2;k<=len;k<<=1)
 44     {
 45         wn=(type>0)?Wn[k]:_Wn[k];
 46         for(i=0;i<len;i+=k)
 47         {
 48             for(j=0,w=1;j<(k>>1);j++,w=w*wn%p)
 49             {
 50                 t=w*s[i+j+(k>>1)]%p;
 51                 s[i+j+(k>>1)]=(s[i+j]+p-t)%p;
 52                 s[i+j]=(s[i+j]+t)%p;
 53             }
 54         }
 55     }
 56 }
 57 void Main(int len,int L)
 58 {
 59     int i,invl=qpow(len,p-2);
 60     NTT(a,len,1,L); NTT(b,len,1,L);
 61     for(i=0;i<len;i++) c[i]=a[i]*b[i]%p;
 62     NTT(c,len,-1,L);
 63     for(i=0;i<len;i++) c[i]=c[i]*invl%p;
 64 }
 65 void clr(int sz)
 66 {
 67     memset(a,0,sz<<3);
 68     memset(b,0,sz<<3);
 69 }
 70 };
 71
 72 using NTT::a; using NTT::b; using NTT::c;
 73 ll F1[N1],F2[N1],f[N1],g[N1],mul[N1],_mul[N1];
 74 void CDQ(int l,int r)
 75 {
 76     if(r-l==1&&l)
 77     {
 78         F1[l]=(f[l]*mul[l-1]%p+qpow(l,l-2))%p;
 79         f[l]=F1[l]*_mul[l]%p;
 80     }
 81     if(r-l<=1) return;
 82     int mid=(l+r)>>1,i,len,L;
 83     CDQ(l,mid);
 84     for(len=1,L=0;len<(mid-l)+(r-l)-1;len<<=1,L++);
 85     for(i=l;i<mid;i++) NTT::a[i-l]=f[i];
 86     for(i=0;i<(r-l);i++) NTT::b[i]=g[i];
 87     NTT::Main(len,L);
 88     for(i=mid;i<r;i++) f[i]=(f[i]+NTT::c[i-l])%p;
 89     NTT::clr(len);
 90     CDQ(mid,r);
 91 }
 92 int v[5][N1],sz[5];
 93
 94 int main()
 95 {
 96     scanf("%d",&T);
 97     int i,j,x,y,len,L,t;
 98     for(t=0;t<T;t++)
 99     {
100         sz[t]=gint();
101         for(i=1;i<=sz[t];i++) v[t][i]=gint(), n=max(n,v[t][i]);
102     }
103     for(len=1,L=0;len<n+n-1;len<<=1,L++);
104     NTT::Pre(len,L);
105     mul[0]=mul[1]=_mul[0]=_mul[1]=1;
106     for(i=2;i<=n;i++) mul[i]=mul[i-1]*i%p, _mul[i]=qpow(mul[i],p-2);
107     for(i=2,g[1]=1;i<=n;i++) g[i]=qpow(i,i-2)*_mul[i-1]%p;
108     CDQ(0,n+1);
109     for(i=0;i<=n;i++) NTT::a[i]=F1[i]*_mul[i]%p;  NTT::a[0]=1; // f[j] / (j-1)!
110     for(i=2;i<=n;i++) NTT::b[i]=qpow(i,i-2)*_mul[i-2]%p; // j^(j-2) / (j-2)!  NTT::b[1]=1;
111     NTT::Main(len,L);  F2[1]=1;
112     for(i=2;i<=n;i++) F2[i]=mul[i-2]*NTT::c[i]%p;
113     for(t=0;t<T;t++)
114     {
115         ll ans=qpow(2,sz[t]),ret=1;
116         for(i=1;i<=sz[t];i++) ans=ans*F1[v[t][i]]%p;
117         for(i=1;i<=sz[t];i++) ret=ret*F2[v[t][i]]%p;
118         ans=(ans+p-ret)%p;
119         printf("%lld\n",ans);
120     }
121     return 0;
122
123 }  

原文地址:https://www.cnblogs.com/guapisolo/p/10354683.html

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

HDU 5279 YJC plays Minecraft (分治NTT优化DP)的相关文章

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) 的对应

ZOJ 3874 Permutation Graph (分治NTT优化DP)

题面:vjudge传送门 ZOJ传送门 题目大意:给你一个排列,如果两个数构成了逆序对,就在他们之间连一条无向边,这样很多数会构成一个联通块.现在给出联通块内点的编号,求所有可能的排列数 推来推去容易发现性质,同一联通块内的点一定是连续标号的,否则无解 然后我就不会了 好神的$NTT$优化$DP$啊 根据上面的性质,联通块之间是互不影响的,所以我们对每个联通块分别统计答案再相乘 定义$f[i]$表示$i$个点构成的合法联通块,可能的排列数 一个合法联通块的所有元素一定在同一联通块内,说明不可能存

HDU 5322 Hope (分治NTT优化DP)

题面传送门 题目大意: 假设现在有一个排列,每个数和在它右面第一个比它大的数连一条无向边,会形成很多联通块. 定义一个联通块的权值为:联通块内元素数量的平方. 定义一个排列的权值为:每个联通块的权值之积 求长度为$n$所有排列的权值之和,$n\leq 1e5$,$1e4$组询问 原题面描述不清楚啊..害得我白想了30min 和ZOJ3874一样都是排列$DP$问题 $DP$方程还是不难想的 假设现在有一个$i-1$的排列,当我们把$i$某个位置上时 $i$前面的数都会和$i$连通,$i$后面的数

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 2993 MAX Average Problem (斜率优化dp入门)

MAX Average Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5855    Accepted Submission(s): 1456 Problem Description Consider a simple sequence which only contains positive integers as

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小.求这个权值和. 输入 第一行一个正整数 $n$ . 第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值. 输出 输出一行一个数表示改造后的最短引爆时间. 样例输入 99 5 3 7 6 9

HDU 3842 Machine Works cdq分治 斜率优化

本题是利用cdq分治  实现斜率优化的一个题目 斜率优化之前做的几个题都是斜率单调,并且插入点时由于点在某一维单调,所以仅仅操作队首和队尾就能完成优化了 但是本题显然不是 主要参考了两个东西 从<Cash>谈一类分治算法的应用 (Day1)cdq分治相关 这两个直接在百度上搜 ,第一个出来的就是 本题的题意是 一个公司获得了一个厂房n(10^5)天的使用权 和一笔启动资金C(10^9),准备在n天里租借机器生产来获得收益 可以租借的机器有M(10^5)个,每个机器有四个值,D,P,R,G (D

【BZOJ-3672】购票 树分治 + 斜率优化DP

3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1177  Solved: 562[Submit][Status][Discuss] Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接.为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号.

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器