[BZOJ 4332] [JSOI2012]分零食(DP+FFT)

题面

同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U。如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\(f(x)=Ox^2+Sx+U\)

现在校长开始分糖果了,一共有M个糖果。有些小朋友可能得不到糖果,对于那些得不到糖果的小朋友来说,欢乐程度就是1。如果一位小朋友得不到糖果,那么在她身后的小朋友们也都得不到糖果。(即这一列得不到糖果的小朋友一定是最后的连续若干位)

所有分糖果的方案都是等概率的。现在问题是:期望情况下,所有小朋友的欢乐程度的乘积是多少?呆呆同学很快就有了一个思路,只要知道总的方案个数T和所有方案下欢乐程度乘积的总和S,就可以得到答案Ans=S/T。现在他已经求出来了T的答案,但是S怎么求呢?他就不知道了。你能告诉他么?

因为答案很大,你只需要告诉他S对P取模后的结果。

分析

题面osu好评

设\(dp[i][j]\)表示i个人里分j个零食得到的答案

那么$$dp[i][j]=\sum_{k=0}^{j} dp[i-1][j-k] f(j)$$

初始值\(dp[0][j]=1\)

暴力递推是\(O(nm^2)\)的,我们发现后面的式子是一个卷积的形式,即\(dp_i=dp_{i-1}*f\)

由于卷积满足结合律,\(dp_i=dp_0 * f^i=1*f^i=f^i\).但是我们要求的是\(\sum_{i=1}^n dp[n][m]\),单点求值用FFT可以做到\(O(m \log m \log n)\),求和的复杂度是\(O(nm \log m \log n)\).因此,我们考虑快速幂分治的思想,想办法把问题范围缩小一半。

令\(s_n=\sum_{i=1}^n dp_i\)

则$$s_n=s_{\frac{n}{2}}+\sum_{i=\frac{n}{2}+1}^n dp_i=s_{\frac{n}{2}}+\sum_{i=\frac{n}{2}+1}^n fi=s_{\frac{n}{2}}+\sum_{i=1}{n/2} f^{i+n/2}$$

\[=s_{\frac{n}{2}}+f^{\frac{n}{2}}*\sum_{i=1}^{\frac{n}{2}} f^{i}
\]

注意到\(f^{\frac{n}{2}}=dp_{\frac{n}{2}},\sum_{i=1}^{n/2} f^{i}=s_{\frac{n}{2}}\)那么

\[s_n=s_{\frac{n}{2}}+dp_{\frac{n}{2}}*s_{\frac{n}{2}}
\]

类似快速幂倍增一下即可,答案就是\(s[n][m]\)

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<complex>
  5. #define maxn 300000
  6. #include<cmath>
  7. using namespace std;
  8. typedef complex<double> com;
  9. typedef long long ll;
  10. const double pi=acos(-1.0);
  11. int n,m;
  12. ll O,S,U;
  13. ll mod;
  14. void fft(com *x,int *rev,int n,int type){
  15. for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
  16. for(int len=1;len<n;len*=2){
  17. int sz=len*2;
  18. com wn1=com(cos(2*pi/sz),type*sin(2*pi/sz));
  19. for(int l=0;l<n;l+=sz){
  20. int r=l+len-1;
  21. com wnk=com(1,0);
  22. for(int i=l;i<=r;i++){
  23. com tmp=x[i+len];
  24. x[i+len]=x[i]-tmp*wnk;
  25. x[i]=x[i]+tmp*wnk;
  26. wnk*=wn1;
  27. }
  28. }
  29. }
  30. }
  31. struct poly{
  32. int len;
  33. ll arr[maxn+5];
  34. inline int size(){
  35. return len;
  36. }
  37. inline ll & operator [](int i){
  38. return arr[i];
  39. }
  40. friend void operator += (poly &p,poly &q){
  41. for(int i=0;i<=p.len;i++){
  42. p.arr[i]=(p.arr[i]+q.arr[i])%mod;
  43. }
  44. }
  45. void print(){
  46. for(int i=0;i<=len;i++) printf("%d ",arr[i]);
  47. printf("\n");
  48. }
  49. };
  50. int rev[maxn+5];
  51. com tmpa[maxn+5],tmpb[maxn+5],tmpc[maxn+5];
  52. void mul(poly &a,poly &b,poly &c){
  53. int tn=1,k=0;
  54. while(tn<=a.len*2){
  55. k++;
  56. tn*=2;
  57. }
  58. for(int i=0;i<tn;i++){
  59. rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
  60. tmpa[i]=tmpb[i]=tmpc[i]=0;
  61. }
  62. for(int i=0;i<=a.len;i++){
  63. tmpa[i]=a[i];
  64. tmpb[i]=b[i];
  65. }
  66. fft(tmpa,rev,tn,1);
  67. fft(tmpb,rev,tn,1);
  68. for(int i=0;i<tn;i++) tmpc[i]=tmpa[i]*tmpb[i];
  69. fft(tmpc,rev,tn,-1);
  70. for(int i=0;i<=a.len;i++) c[i]=(ll)(tmpc[i].real()/tn+0.5)%mod;
  71. }
  72. poly f,g,tmp,a;
  73. inline void fast_pow(int k){
  74. if(k==1){
  75. f.len=g.len=m;
  76. tmp.len=m;
  77. for(int i=0;i<=m;i++) f[i]=g[i]=a[i];
  78. return;
  79. }
  80. fast_pow(k>>1);
  81. // f.print();
  82. // g.print();
  83. mul(f,g,tmp);
  84. // tmp.print();
  85. f+=tmp;
  86. mul(g,g,g);
  87. if(k&1){
  88. mul(g,a,g);
  89. f+=g;
  90. }
  91. }
  92. inline ll calc(ll x){
  93. return O*x*x%mod+S*x%mod+U%mod;
  94. }
  95. int main(){
  96. scanf("%d %lld",&m,&mod);
  97. scanf("%d %lld %lld %lld",&n,&O,&S,&U);
  98. for(int i=1;i<=m;i++) a[i]=calc(i)%mod;
  99. //注意a[0]=0,而不是calc(0),因为分到0的快乐度是1,对答案无影响,不用累加
  100. fast_pow(n);
  101. printf("%lld\n",f[m]);
  102. }

[BZOJ 4332] [JSOI2012]分零食(DP+FFT)的更多相关文章

  1. 【BZOJ 4332】 4332: JSOI2012 分零食 (FFT+快速幂)

    4332: JSOI2012 分零食 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 119  Solved: 66 Description 这里是欢乐 ...

  2. BZOJ 4332: JSOI2012 分零食 FFT+分治

    好题好题~ #include <bits/stdc++.h> #define N 50020 #define ll long long #define setIO(s) freopen(s ...

  3. bzoj 4332: JSOI2012 分零食 快速傅立叶变换

    题目: Description 同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U.如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\(f(x)=O*x^2+S*x+U\) 现 ...

  4. bzoj千题计划309:bzoj4332: JSOI2012 分零食(分治+FFT)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4332 因为如果一位小朋友得不到糖果,那么在她身后的小朋友们也都得不到糖果. 所以设g[i][j] ...

  5. bzoj 4332:JSOI2012 分零食

    描述 这里是欢乐的进香河,这里是欢乐的幼儿园. 今天是2月14日,星期二.在这个特殊的日子里,老师带着同学们欢乐地跳着,笑着.校长从幼儿园旁边的小吃店买了大量的零食决定分给同学们.听到这个消息,所有同 ...

  6. 【bzoj4332】【JSOI2012】 分零食 生成函数 FFT

    我们构造$f(x)$的生成函数$G(x)$,那么显然$[x^k]G(x)=Ok^2+Sk+U$ 那么显然,答案即为$\sum_{i=1}^{n} [x^m]G^i(x)$ 我们构造答案的生成函数$F( ...

  7. bzoj4332;vijos1955:JSOI2012 分零食

    描述 这里是欢乐的进香河,这里是欢乐的幼儿园. 今天是2月14日,星期二.在这个特殊的日子里,老师带着同学们欢乐地跳着,笑着.校长从幼儿园旁边的小吃店买了大量的零食决定分给同学们.听到这个消息,所有同 ...

  8. BZOJ4332 JSOI2012 分零食 【倍增 + NTT】

    题目链接 权限题BZOJ4332 题解 容易想到\(dp\) 设\(g[i][j]\)表示前\(i\)人分到\(j\)颗糖的所有方案的乘积之和 设\(f(x) = Ox^2 + Sx + U\) \[ ...

  9. bzoj4332[JSOI2012]分零食

    一下午被这题的精度续掉了...首先可以找出一个多项式的等比数列的形式,然后类似poj的Matrix Series,不断倍增就可以了.用复数点值表示进行多次的多项式运算会刷刷地炸精度...应当用int存 ...

随机推荐

  1. 【leetcode】Valid Palindrome II

    很久没有做题了,今天写个简单难度的练练手感. Given a non-empty string s, you may delete at most one character. Judge wheth ...

  2. python 使用嵌套函数报local variable xxx referenced before assignment或者 local variable XXX defined in enclosing scope

    情况一: a 直接引用外部的,正常运行 def toplevel(): a = 5 def nested(): print(a + 2) # theres no local variable a so ...

  3. @ENABLECACHING 基于注解的缓存

    @EnableCaching• @Cacheable指定一个或多个Cache名字,同属性cacheNamesSpring Cache 使用 ---@EnableCaching @Cacheable 注 ...

  4. @JsonView注解指定返回的model类中显示的字段

    1.User类 package com.imooc.model; import com.fasterxml.jackson.annotation.JsonView; /** * @author oy ...

  5. Debian Buster升级后找不到声卡

    昨天将Debian从Stretch升级到了新版巴斯光年(Buster).仍旧是先将source.list中的stretch替换为buster,再执行apt-get的update.upgrade.dis ...

  6. 【Leetcode】买卖股票-贪心算法

    题目: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多笔交易(你必 ...

  7. django model序列化作用举例

    一直对使用DRF的了解停留在一知半解的状态,今天在实际操作中,感受到了DRF带来的方便 Django工程,其中两个model定义如下: AutomationHeadRaw: class Automat ...

  8. selenium+常见操作

    1.多窗口操作 有些页面的链接打开后,会重新打开一个窗口,对于这种情况,想在新页面上操作,就得先切换窗口了.获取窗口的唯一标识用句柄表示,所以只需要切换句柄,我们就能在多个页面上灵活自如的操作了. 句 ...

  9. C++二维数组(指针)做参数

    一.问题描述 使用C++编程过程中经常需要使用到二维数组,然而初级程序员在使用过程中经常会出错使程序崩溃.下面就二维指针的定义,初始化,以及二维指针做参数给出简单介绍. 1.二维数组的定义与初始化 在 ...

  10. spring cloud:config-eureka-refresh

    config-server-eureka project 1. File-->new spring project 2.add dependency <parent> <gro ...