题面

传送门

思路

首先,这个数据如果没有这么大,我们还是可以做朋友的......

设$dp\left[i\right]\left[j\right]$代表前j个零食分给了前i个人的方案数

那么dp方程显然:

$dp\left[i\right]\left[j\right]=\sum_{k=1}^{j-1} dp\left[i-1\right]\left[k\right]+f\left(j-k\right)$

其中$f\left(x\right)$就是题目里给的那个二次函数

同时有一个性质:

$dp\left[i\right]\left[j\right]=dp\left[\frac i2\right]\left[k\right]\ast dp\left[\frac i2\right]\left[j-k\right]$

显然这道题不能直接O(nm)递推......那我们换个办法来想

n辣么大,为什么我们不考虑 一下用倍增的方法呢?正好上面那个性质可以利用一下

并且还应当注意,我们最后要求的是$\sum_{i=1}^n dp\left[i\right]\left[m\right]$

所以我们设$p\left[i\right]\left[j\right]=\sum_{k=1}^n dp\left[k\right]\left[j\right]$

$p\left[i\right]\left[j\right]=p\left[\frac i2\right]\left[j\right]+\sum_{k=1}^{\frac i2}dp\left[k+\frac i2\right]\left[j\right]$

$p\left[i\right]\left[j\right]=p\left[\frac i2\right]\left[j\right]+\sum_{k=1}^{\frac i2}\sum_{l=1}^{j-1}dp\left[k\right]\left[l\right]dp\left[\frac i2\right]\left[j-l\right]$

$p\left[i\right]\left[j\right]=p\left[\frac i2\right]\left[j\right]+\sum_{l=1}{j-1}\sum_{k=1}{\frac i2}dp\left[k\right]\left[l\right]dp\left[\frac i2\right]\left[j-l\right]$

$p\left[i\right]\left[j\right]=p\left[\frac i2\right]\left[j\right]+\sum_{l=1}^{j-1}dp\left[\frac i2\right]\left[j-l\right]\sum_{k=1}^{\frac i2}dp\left[k\right]\left[l\right]$

$p\left[i\right]\left[j\right]=p\left[\frac i2\right]\left[j\right]+\sum_{l=1}^{j-1}dp\left[\frac i2\right]\left[j-l\right]p\left[\frac i2\right]\left[l\right]$

也就是说p可以由上一层的p加上一层的dp与p的卷积得到,而dp可以由上一层的dp自乘得到

那么自然可以用倍增p的第一层参数的方法,用FFT优化一下,一直做到n

时间效率为$O\left(mlogmlogn\right)$

注意:将n转化为二进制,那么为一的那些位,要在倍增完以后再推一层

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
struct complex{
double x,y;
complex(double xx=0,double yy=0){x=xx;y=yy;}
complex operator +(const complex &b){return complex(x+b.x,y+b.y);}
complex operator -(const complex &b){return complex(x-b.x,y-b.y);}
complex operator *(const complex &b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
}A[100010],B[100010];
const double pi=acos(-1.0);
int n,m,limit=1,cnt=0,r[100010];
int MOD;
void fft(complex *a,double type){
int i,j,k,mid;complex x,y,wn,w;
for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(mid=1;mid<limit;mid<<=1ll){
wn=complex(cos(pi/mid),type*sin(pi/mid));
for(j=0;j<limit;j+=(mid<<1ll)){
w=complex(1,0);
for(k=0;k<mid;k++,w=w*wn){
x=a[j+k];y=a[j+k+mid]*w;
a[j+k]=x+y;a[j+k+mid]=x-y;
}
}
}
}
int now=1,w=0,g[100010]={0},p[100010]={0},f[100010]={0};
int a1,a2,a3;
void solve1(){
int i;
for(i=0;i<=limit;i++) A[i]=B[i]=complex(0,0);
for(i=0;i<=limit;i++) A[i].x=p[i],B[i].x=g[i];
fft(A,1);fft(B,1);
for(i=0;i<=limit;i++) A[i]=A[i]*B[i];
fft(A,-1);
for(i=1;i<=m;i++) p[i]=(p[i]+(int)(A[i].x/limit+0.5)%MOD)%MOD; for(i=0;i<=limit;i++) A[i]=complex(0,0);
for(i=0;i<=limit;i++) A[i].x=g[i];
fft(A,1);
for(i=0;i<=limit;i++) A[i]=A[i]*A[i];
fft(A,-1);
for(i=1;i<=m;i++) g[i]=(int)(A[i].x/limit+0.5)%MOD;
}
void solve2(){
int i;
for(i=0;i<=limit;i++) A[i]=B[i]=complex(0,0);
for(i=1;i<=m;i++) A[i].x=f[i],B[i].x=g[i];
fft(A,1);fft(B,1);
for(i=0;i<=limit;i++) A[i]=A[i]*B[i];
fft(A,-1);
for(i=1;i<=m;i++) g[i]=(int)(A[i].x/limit+0.5)%MOD,p[i]=(p[i]+g[i])%MOD;
}
int main(){
m=read();MOD=read();n=read();a1=read();a2=read();a3=read();
int i;
a1%=MOD;a2%=MOD;a3%=MOD;
for(i=1;i<=m;i++) g[i]=p[i]=f[i]=((((((a1*i)%MOD)*i)%MOD)+a2*i%MOD)+a3)%MOD;
while(limit<=(m<<1ll)) limit<<=1ll,cnt++;
for(i=0;i<limit;i++) r[i]=((r[i>>1ll]>>1ll)|((i&1ll)<<(cnt-1ll)));
while((now<<1ll)<=n) now<<=1ll,w++;
while(w){
w--;
solve1();//倍增
if(n&(1<<w)) solve2();//这一位应该是个奇数的,再推一层
}
printf("%lld\n",p[m]%MOD);
}

[JSOI2012][bzoj4332] 分零食 [FFT]的更多相关文章

  1. FFT 【JSOI2012】bzoj4332 分零食 (未解决)

    很不错的一道倍增优化dp?? 第一次做这类题挺难想的 题目大意: 有n个小朋友,m块糖. 给小朋友分糖,如果一个小朋友分不到糖,那他后面的小朋友也分不到糖. 每个小朋友有一个喜悦值,有三个参数,O,S ...

  2. 【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( ...

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

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

  4. LGP5075【JSOI2012】分零食

    . 题解: 令$F$为欢乐度$f(x) = Ox^2 + Sx + U$的生成函数,常数项为$0$: 令$G(x) = \sum_{i=0}^{A} F^i (x) $ $ans = [x^M]G;$ ...

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

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

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

    [BZOJ 4332] [JSOI2012]分零食(DP+FFT) 题面 同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U.如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\ ...

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

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

  8. bzoj4332;vijos1955:JSOI2012 分零食

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

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

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

随机推荐

  1. 【转】IOS开发网络篇之──ASIHTTPRequest详解

    ASIHTTPRequest 详解, http 请求终结者 版权归旺财勇士所有〜转载需声名〜 原贴地地址:http://wiki.magiche.net/pages/viewpage.action?p ...

  2. Java环境变量搭建(Windows环境)

    变量名:JAVA_HOME 变量值:C:\Program Files (x86)\Java\jdk1.8.0_91        // 要根据自己的实际路径配置 变量名:CLASSPATH 变量值:. ...

  3. java 代码优化

    Java程序中的内存管理机制是通过GC完成的,“一个对象创建后被放置在JVM的堆内存中,当永远不在应用这个对象的时候将会被JVM在堆内存中回收.被创建的对象不能再生,同时也没有办法通过程序语句释放”( ...

  4. Vue3.0脚手架搭建

    https://www.jianshu.com/p/fbcad30031c2 vue3.0官网:https://cli.vuejs.org/zh/guide/ 介绍: notice: 这份文档是对应 ...

  5. 1047: [HAOI2007]理想的正方形

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4075  Solved: 2277[Submit][Status][Discuss] Descript ...

  6. 十三、MySQL WHERE 子句

    MySQL WHERE 子句 我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据. 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中. 语法 以下是 ...

  7. flock文件锁

    linux中的定时任务crontab会定时执行一些脚本,但是脚本的时间往往无法控制,当脚本的执行时间过长,可能会导致上一次任务的脚本还没执行完,下一次任务的脚本又开始执行的问题.这种情况下会出现一些并 ...

  8. php微信红包算法

    微信红包算法.php /**生成红包的函数*/ function getRandMoney($totalMoney, $totalPeople=2, $miniMoney=1){ $randRemai ...

  9. 5904.刺客信条(AC)

    Description           故事发生在1486 年的意大利,Ezio 原本只是一个文艺复兴时期的贵族,后来因为家族成员受到圣殿骑士的杀害,决心成为一名刺客.最终,凭借着他的努力和出众的 ...

  10. Python的三种基本数据类型

    数字 int(整型) long(长整型),python对长整型没有限制,理论上可以无限大.python3后没有long了. float   字符串   加了引号的都是字符串.   单引号和双引号没有约 ...