[BZOJ 4332] [JSOI2012]分零食(DP+FFT)
[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}$$
\]
注意到\(f^{\frac{n}{2}}=dp_{\frac{n}{2}},\sum_{i=1}^{n/2} f^{i}=s_{\frac{n}{2}}\)那么
\]
类似快速幂倍增一下即可,答案就是\(s[n][m]\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<complex>
#define maxn 300000
#include<cmath>
using namespace std;
typedef complex<double> com;
typedef long long ll;
const double pi=acos(-1.0);
int n,m;
ll O,S,U;
ll mod;
void fft(com *x,int *rev,int n,int type){
for(int i=0;i<n;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
for(int len=1;len<n;len*=2){
int sz=len*2;
com wn1=com(cos(2*pi/sz),type*sin(2*pi/sz));
for(int l=0;l<n;l+=sz){
int r=l+len-1;
com wnk=com(1,0);
for(int i=l;i<=r;i++){
com tmp=x[i+len];
x[i+len]=x[i]-tmp*wnk;
x[i]=x[i]+tmp*wnk;
wnk*=wn1;
}
}
}
}
struct poly{
int len;
ll arr[maxn+5];
inline int size(){
return len;
}
inline ll & operator [](int i){
return arr[i];
}
friend void operator += (poly &p,poly &q){
for(int i=0;i<=p.len;i++){
p.arr[i]=(p.arr[i]+q.arr[i])%mod;
}
}
void print(){
for(int i=0;i<=len;i++) printf("%d ",arr[i]);
printf("\n");
}
};
int rev[maxn+5];
com tmpa[maxn+5],tmpb[maxn+5],tmpc[maxn+5];
void mul(poly &a,poly &b,poly &c){
int tn=1,k=0;
while(tn<=a.len*2){
k++;
tn*=2;
}
for(int i=0;i<tn;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
tmpa[i]=tmpb[i]=tmpc[i]=0;
}
for(int i=0;i<=a.len;i++){
tmpa[i]=a[i];
tmpb[i]=b[i];
}
fft(tmpa,rev,tn,1);
fft(tmpb,rev,tn,1);
for(int i=0;i<tn;i++) tmpc[i]=tmpa[i]*tmpb[i];
fft(tmpc,rev,tn,-1);
for(int i=0;i<=a.len;i++) c[i]=(ll)(tmpc[i].real()/tn+0.5)%mod;
}
poly f,g,tmp,a;
inline void fast_pow(int k){
if(k==1){
f.len=g.len=m;
tmp.len=m;
for(int i=0;i<=m;i++) f[i]=g[i]=a[i];
return;
}
fast_pow(k>>1);
// f.print();
// g.print();
mul(f,g,tmp);
// tmp.print();
f+=tmp;
mul(g,g,g);
if(k&1){
mul(g,a,g);
f+=g;
}
}
inline ll calc(ll x){
return O*x*x%mod+S*x%mod+U%mod;
}
int main(){
scanf("%d %lld",&m,&mod);
scanf("%d %lld %lld %lld",&n,&O,&S,&U);
for(int i=1;i<=m;i++) a[i]=calc(i)%mod;
//注意a[0]=0,而不是calc(0),因为分到0的快乐度是1,对答案无影响,不用累加
fast_pow(n);
printf("%lld\n",f[m]);
}
[BZOJ 4332] [JSOI2012]分零食(DP+FFT)的更多相关文章
- 【BZOJ 4332】 4332: JSOI2012 分零食 (FFT+快速幂)
4332: JSOI2012 分零食 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 119 Solved: 66 Description 这里是欢乐 ...
- BZOJ 4332: JSOI2012 分零食 FFT+分治
好题好题~ #include <bits/stdc++.h> #define N 50020 #define ll long long #define setIO(s) freopen(s ...
- bzoj 4332: JSOI2012 分零食 快速傅立叶变换
题目: Description 同学们依次排成了一列,其中有A位小朋友,有三个共同的欢乐系数O,S和U.如果有一位小朋友得到了x个糖果,那么她的欢乐程度就是\(f(x)=O*x^2+S*x+U\) 现 ...
- bzoj千题计划309:bzoj4332: JSOI2012 分零食(分治+FFT)
https://www.lydsy.com/JudgeOnline/problem.php?id=4332 因为如果一位小朋友得不到糖果,那么在她身后的小朋友们也都得不到糖果. 所以设g[i][j] ...
- bzoj 4332:JSOI2012 分零食
描述 这里是欢乐的进香河,这里是欢乐的幼儿园. 今天是2月14日,星期二.在这个特殊的日子里,老师带着同学们欢乐地跳着,笑着.校长从幼儿园旁边的小吃店买了大量的零食决定分给同学们.听到这个消息,所有同 ...
- 【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( ...
- bzoj4332;vijos1955:JSOI2012 分零食
描述 这里是欢乐的进香河,这里是欢乐的幼儿园. 今天是2月14日,星期二.在这个特殊的日子里,老师带着同学们欢乐地跳着,笑着.校长从幼儿园旁边的小吃店买了大量的零食决定分给同学们.听到这个消息,所有同 ...
- BZOJ4332 JSOI2012 分零食 【倍增 + NTT】
题目链接 权限题BZOJ4332 题解 容易想到\(dp\) 设\(g[i][j]\)表示前\(i\)人分到\(j\)颗糖的所有方案的乘积之和 设\(f(x) = Ox^2 + Sx + U\) \[ ...
- bzoj4332[JSOI2012]分零食
一下午被这题的精度续掉了...首先可以找出一个多项式的等比数列的形式,然后类似poj的Matrix Series,不断倍增就可以了.用复数点值表示进行多次的多项式运算会刷刷地炸精度...应当用int存 ...
随机推荐
- 对浏览器如何计算CSS的研究---------------引用
1. 加载CSS 在构建DOM的过程中,如果遇到link的标签,当把它插到DOM里面之后,就会触发资源加载——根据href指明的链接: 上面的rel指明了它是一个样式文件.这个加载是异步,不会影响DO ...
- vue父组件异步获取动态数据传递给子组件获取不到值
原理: 在父组件中使用axios获取异步数据传给子组件,但是发现子组件在渲染的时候并没有数据,在created里面打印也是空的,结果发现一开始子组件绑定的数据是空的,在请求数据没有返回数据时,子组件就 ...
- js中[]、{}、()区别
一.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数体 {}表示对象.[]表示对象的属性.方法,()如果用在方法名后面,代表调用 如:var LangShen = {&quo ...
- Redis配置文件全解
基本配置 port 6379 # 监听端口号,默认为 6379,如果你设为 0 ,redis 将不在 socket 上监听任何客户端连接. daemonize no #是否以后台进程启动 datab ...
- join的源码
long base = System.currentTimeMills(); long now = 0; if(millis < 0){ throw new IllegalArgumentE ...
- 【后台管理系统】—— Ant Design Pro 页面相关(三)
一.卡片Card分类 与普通卡片使用区别:底部按钮及内容样式 <Card hoverable bodyStyle={{ paddingBottom: 20 }} actions={[ // 卡片 ...
- 数据结构和算法(Java版)快速学习(交换、选择、插入排序)
基本排序算法:交换.选择.插入排序 常用的交换排序又称之为:冒泡排序 一般河水中的冒泡,水底刚冒出来的时候是比较小的,随着慢慢向水面浮起会逐渐增大,冒泡排序由此物理规律得来. 冒泡算法的运作规律如下: ...
- 改变主程序的入口 main
main只是开发工具所规定的一个特殊函数名称而已.它既不是程序的入口,也不是必须要有的函数. 程序的入口点记录在可执行文件中的一个数据,该数据标明程序从哪个位置开始执行,这个数据是连接程序的时候由li ...
- 7、Shiro加密和加盐
这里我们以md5加密方法举例,首先我们写一个main方法测试我们的密码经过md5加密之后的得到什么样的字符串: /** * 书写方法测试Md5Hash将密码“houru”加密之后的密文 * 但是仅仅加 ...
- PHP面向对象-设计模式 单例模式 简单工厂模式 工厂方法模式
1.单例模式 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例.即一个类只有一个对象实例. 要实现每一个类只有一个实例,就需 ...