zoukankan      html  css  js  c++  java
  • HDU 5322 Hope (分治NTT优化DP)

    题面传送门

    题目大意:

    假设现在有一个排列,每个数和在它右面第一个比它大的数连一条无向边,会形成很多联通块。

    定义一个联通块的权值为:联通块内元素数量的平方。

    定义一个排列的权值为:每个联通块的权值之积

    求长度为$n$所有排列的权值之和,$nleq 1e5$,$1e4$组询问

    原题面描述不清楚啊..害得我白想了30min

    ZOJ3874一样都是排列$DP$问题 

    $DP$方程还是不难想的

    假设现在有一个$i-1$的排列,当我们把$i$某个位置上时

    $i$前面的数都会和$i$连通,$i$后面的数一定不和$i$前面的数连通

    利用这个性质就可以$DP$了,定义$f[i]$表示长度为$i$的所有排列的权值之和

    $f[i]$

    $i$后面一共j个数可以在$i-1$个数中任选,$i$前面一共$i-j-1$个数可以任意排列,可得

    $=sum C_{i-1}^{j}f[j](i-j-1)!(i-j)^{2}$

    化简

    $=(i-1)!sum frac{f[j]}{j!}(i-j)^{2}$

    发现这是一个卷积的形式,用分治$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;x=x*x%p,y>>=1) if(y&1) ans=ans*x%p;
     25     return ans;
     26 }
     27 
     28 namespace NTT{
     29 
     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=2;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 
     73 using NTT::a; using NTT::b; using NTT::c;
     74 ll f[N1],g[N1],ans[N1],mul[N1],_mul[N1]; int de;
     75 void CDQ(int l,int r)
     76 {
     77     if(r-l==1&&l>0)
     78     { 
     79         ans[l]=mul[l-1]*f[l]%p; 
     80         f[l]=ans[l]*_mul[l]%p; return; 
     81     }
     82     if(r-l<=1) return;
     83     int mid=(l+r)>>1,i,len,L;
     84     CDQ(l,mid);
     85     for(len=1,L=0;len<(mid-l)+(r-l)-1;len<<=1,L++);
     86     for(i=l;i<mid;i++) NTT::a[i-l]=f[i];
     87     for(i=0;i<(r-l);i++) NTT::b[i]=g[i];
     88     NTT::Main(len,L);
     89     for(i=mid;i<r;i++) f[i]=(f[i]+NTT::c[i-l])%p;
     90     NTT::clr(len);
     91     CDQ(mid,r);
     92 }
     93 int T,n,m;
     94 int que[N1];
     95 
     96 int main()
     97 {
     98     int i,j,x,y,len,L;
     99     n=100001;
    100     for(i=1;i<n;i++) g[i]=1ll*i*i%p;
    101     mul[0]=mul[1]=_mul[0]=_mul[1]=1;
    102     for(i=2;i<n;i++) mul[i]=mul[i-1]*i%p, _mul[i]=qpow(mul[i],p-2);
    103     for(len=1,L=0;len<n+n-1;len<<=1,L++);
    104     NTT::Pre(len,L);
    105     f[0]=1; CDQ(0,n); 
    106     while(scanf("%d",&n)!=EOF)
    107         printf("%lld
    ",ans[n]);
    108     return 0;
    109 
    110 }  
  • 相关阅读:
    函数数组
    编译和链接
    线程详解
    linux内核完全剖析——基于0.12内核-笔记(2)-统一编址和独立编址
    linux内核完全剖析——基于0.12内核-笔记(1)-CPU 数据通信
    input子系统事件处理层(evdev)的环形缓冲区【转】
    NFC驱动调试
    little kernel 小结
    Linux 设备树的解释
    Android中SELinux的TE简介【转】
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10354193.html
Copyright © 2011-2022 走看看