zoukankan      html  css  js  c++  java
  • CF755G PolandBall and Many Other Balls/soj 57送饮料

    题意:长度为n的序列,相邻两个或单独一个可以划分到一个组,每个元素最多处于一个组。

    问恰好分割成k(1<=k<=m)段有多少种方案?

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod=998244353;
     5 const int rt=31;
     6 const int N=300005;
     7 int l,_n,pos[N],n,k,a[N],b[N],c[N],x1[N],x2[N],x3[N],x4[N],w[N],wn,inv_n;
     8 int ksm(int x,int y)
     9 {
    10     int res=1;
    11     while (y) {if (y&1) res=(ll)res*x%mod; x=(ll)x*x%mod; y>>=1;} 
    12     return res; 
    13 }
    14 void init(int n)
    15 {
    16     l=0;
    17     while ((1<<l)<=n) l++;//注意位长的处理,判断条件是(1<<l)<=n 
    18     _n=1<<l;wn=ksm(rt,1<<23-l);
    19     w[0]=1;inv_n=ksm(_n,mod-2);
    20     for (int i=1;i<_n;i++)
    21       w[i]=(ll)w[i-1]*wn%mod,pos[i]=(i&1)?pos[i-1]|(1<<(l-1)):pos[i>>1]>>1;
    22 }
    23 void fft(int *a,int op)
    24 {
    25     for (int i=0;i<_n;i++) if (i<pos[i]) swap(a[i],a[pos[i]]);
    26     int len=1,id=_n;
    27     for (int i=0;i<l;i++)
    28     {
    29       int wn=w[id>>=1];
    30       for (int j=0;j<_n;j+=len*2)
    31         for (int k=j,w=1;k<j+len;k++)
    32         {
    33              int l=a[k],r=(ll)a[k+len]*w%mod;
    34              a[k]=((ll)l+r)%mod;a[k+len]=((ll)l-r+mod)%mod;
    35              w=(ll)w*wn%mod;
    36          }
    37       len<<=1;
    38     }
    39     if (op==-1) {
    40         reverse(a+1,a+_n);
    41         for (int i=0;i<_n;i++) a[i]=(ll)a[i]*inv_n%mod; 
    42     }
    43 }
    44 void merge(int *a,int *b,int *c)
    45 {
    46     c[0]=1;
    47     for (int i=1;i<=k;i++) c[i]=((ll)((ll)b[i]+b[i-1])%mod+a[i-1])%mod; 
    48     for (int i=k+1;i<_n;i++) c[i]=0;
    49 } 
    50 void solve(int n)
    51 {
    52     if (n==0)
    53     {
    54         a[0]=1;for (int i=1;i<_n;i++) a[i]=0;
    55         b[0]=b[1]=1;for (int i=2;i<_n;i++) b[i]=0;
    56         return;
    57     }
    58     if (n==1)
    59     {
    60         a[0]=a[1]=1;for (int i=2;i<_n;i++) a[i]=0;
    61         b[0]=b[2]=1;b[1]=3;for (int i=3;i<_n;i++) b[i]=0;
    62         return;
    63     }
    64     solve(n/2-1);
    65     merge(a,b,c);
    66    for (int i=k+1;i<_n;i++) a[i]=b[i]=0;
    67    fft(a,1);fft(b,1);fft(c,1);
    68    for (int i=0;i<_n;i++)
    69    {
    70        x1[i]=(ll)a[i]*a[i]%mod;
    71        x2[i]=(ll)b[i]*b[i]%mod;
    72        x3[i]=(ll)a[i]*b[i]%mod;
    73        x4[i]=(ll)b[i]*c[i]%mod;
    74     }
    75     fft(x1,-1);fft(x2,-1);fft(x3,-1);fft(x4,-1);
    76     for (int i=1;i<_n;i++)//从1开始,注意边界 
    77       x2[i]=((ll)x2[i]+x1[i-1])%mod,x4[i]=((ll)x4[i]+x3[i-1])%mod;
    78     if (n&1)
    79     {
    80         merge(x2,x4,b);
    81         for (int i=0;i<_n;i++) a[i]=x4[i];
    82     }else 
    83       for (int i=0;i<_n;i++) a[i]=x2[i],b[i]=x4[i];
    84 }
    85 int main()
    86 {
    87     scanf("%d%d",&n,&k);
    88     init(2*k+1); solve(n);
    89     for (int i=1;i<=k;i++) printf("%d ",a[i]);
    90     puts("");
    91    return 0;
    92 }
    View Code

    题解:fft+分治+dp

    可以得到递推式:f[i(元素数)][j(段)]=f[i-1][j-1]+f[i-2][j-1]+f[i-1][j]

     

    f(n)=f(n-1)*(1+x)+f(n-2)*x.

    一个方法是带权斐波那契通项展开,并不会多项式开根。

    另一个方法,考虑f(a+b)=f(a)*f(b)+f(a-1)*f(b-1)*x。(根据在a,b处能否断开讨论)

    分治下去,f(i),f(i+1)->f(i+2) f(2i+2)=f(i+1)*f(i+1)+f(i)*f(i)*x 

    f(2i+3)=f(i+1)*f(i+2)+f(i)*f(i+1)*x  f(2i+4)=f(i+2)*f(i+2)+f(i+1)*f(i+1)*x

    注意n的奇偶要讨论,m以后的k不用计算。时间复杂度O(mlog^2(m))。

     

  • 相关阅读:
    Ceph中的容量计算与管理
    Ceph Monitor基础架构与模块详解
    Ceph:pg peering过程分析
    API调用过程
    Windows内核—保护模式
    逆向笔记——C、C++对应的汇编结构(一)
    2020年内网渗透培训:红队攻防
    2020年 初级渗透工程师【Web安全方向】
    渗透测试【网络安全】入门指南【20190607】
    渗透学习问题【一】遇到坑需要停下来补吗
  • 原文地址:https://www.cnblogs.com/Scx117/p/9158878.html
Copyright © 2011-2022 走看看