[hdu5307] He is Flying [FFT+数学推导]
题面
思路
看到这道题,我的第一想法是前缀和瞎搞,说不定能$O\left(n\right)$?
事实证明我的确是瞎扯......
题目中的提示
这道题的数据中告诉了我们:
$sum\left(s\left[i\right]\right)<=50000$
也就是说,总长度是很小的,这提示我们往“通过长度来解题”的方向上想
那么,最便捷的处理区间长度和的算法是什么呢?前缀和
我们需要求什么?
做题的过程中,一定不能忘记这一点:我们要求的是,所有长度为s的区间的愉悦值总和
那么,一个长度为s的区间,在关于长度的前缀和pre中是怎么表示的呢?
就是所有的$pre[i]-pre[i-s]$,也就是它们下标之差是一定的
下标差一定......不同的决策之和......
FFT卷积!
FFT
我们考虑一个前缀和数组$pre$,范围从$0$到$sum(s[i])$,将它反向成为$antipre$,那么有:
$pre[i]=antipre[n-i+1]$
显然,当我们把$pre[i]$作为一个多项式$A$的$x{i+1}$项的系数,把$antipre[i]$作为另一个多项式$B$的$x{i+1}$项的系数时,将两个多项式乘起来,那么得到的新多项式$C$的第$x^{i+2}$项的系数,就保存了关于所有长度为i+1的区间的信息
保存什么信息?
题目中描述了,可能有区间的长度为0,也就是说,前缀和中的同一个长度数值上可能有多个点
我们设前缀和长度为s的一共有$tot[s]$个点,最左边的是$l[s]$,最右边的是$r[s]$
那么对于一段长度为s的,我们的信息来自于$pre[i]$和$pre[i-s]$
假设我们当前要求rr-s这个长度和rr这个长度的信息,那么我们来考虑一下它们总共的贡献值是多少
$l1,r1$就是$l[rr-s]$和$r[rr-s]$,$l2,r2$同理
那么总的愉悦值贡献$contribution$应该是这样的:
$contribution=\sum_{i=l1}{r1}\sum_{j=l2}{r2}\left(j-i+1\right)$
$contribution=pq+\sum_{j=l2}{r2}jp-\sum_{i=l1}{r1}iq$
$contribution=pq+\frac{pq\left(r2+l2\right)}2-\frac{qp\left(l1+r1\right)}2$
$contribution=\frac 12pq\left(l2-l1+r2-r1+2\right)$
因为前缀和求区间$[l,r]$是减掉第l-1项的,所以上式中的$pq$项抵消掉了
因此
$contribution=\frac 12pq\left(l2-l1+r2-r1\right)$
这个东西显然可以两次FFT相减来处理
总结
本题到了这里就结束了
纵观整个过程,我们从题目要求的东西,想到使用前缀和,又从需要对前缀和处理什么得到使用FFT的方法,最后用数学推导得到了FFT的方法
换句话说,整个解题过程中我们的每一步操作都是有迹可循、有原因的,不是因为“我见过这种题所以用FFT”——总会有你没见过的题出现
解题的过程、建模的过程是一个不断修正矛盾(问题)的过程,这个矛盾既可以是时间矛盾、正确性矛盾,也可以是代码编写复杂度的矛盾,但是核心的一点就是:矛盾的修正要有方向性、有依据
一定是因为这里不对了我才去优化,而不是一上来就瞎猜一个高级方法然后硬想,那样想破了脑袋都想不出来
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
inline ll read(){
ll 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<<1ll)+(re<<3ll)+ch-'0',ch=getchar();
return re*flag;
}
struct complex{
long double x,y;
complex(long double xx=0,long 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[300010],B[300010];
const long double pi=acos(-1.0);
ll n,m,limit=1,cnt=0,r[300010];
void fft(complex *a,long double type){
ll 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;
}
}
}
if(type==-1) for(i=0;i<=limit;i++) a[i].x=(ll)(a[i].x/limit+0.1);
}
ll tot[50010],s[100010],L[100010],R[100010];
ll ans[100010];
int main(){
ll T=read(),i,j,sum,tmp;
while(T--){
n=read();sum=0;memset(ans,0,sizeof(ans));memset(tot,0,sizeof(tot));tot[0]=1;
memset(L,127,sizeof(L));memset(R,0,sizeof(R));L[0]=0;memset(s,0,sizeof(s));
for(i=1;i<=n;i++){
s[i]=read(),tot[sum+=s[i]]++;
L[sum]=min(L[sum],i);R[sum]=max(R[sum],i);
}
tmp=0;
for(i=1;i<=n;i++){
if(s[i]) tmp=0;
else tmp++,ans[0]+=(ll)(tmp*(tmp+1)/2ll);
}//0要特殊处理,我们的算法并不能得到零的解,这一点具体是为什么,可以自己推导一下,会发现最后所有0的项的解都自我抵消掉了
memset(r,0,sizeof(r));
while(limit<=(sum<<1)) limit<<=1,cnt++;
for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
memset(A,0,sizeof(A));memset(B,0,sizeof(B));
for(i=0;i<=sum;i++) A[i+1].x=tot[i]*(L[i]+R[i])/2.0,B[i+1].x=tot[sum-i];//减去l1r1
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<=sum;i++) ans[i]-=(ll)A[sum+2-i].x;
memset(A,0,sizeof(A));memset(B,0,sizeof(B));
for(i=0;i<=sum;i++) A[i+1].x=tot[i],B[i+1].x=tot[sum-i]*(L[sum-i]+R[sum-i])/2.0;//加上r2l2
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<=sum;i++) ans[i]+=(ll)A[sum+2-i].x;
//整个过程中,因为我们分析的公式是针对区间[l,r]的l和r的,但是算法实现的时候是针对l-1和r的(前缀和思想),所以原式中要去掉那个p*q
for(i=0;i<=sum;i++) printf("%lld\n",ans[i]);
}
}
[hdu5307] He is Flying [FFT+数学推导]的更多相关文章
- HDU-5307 He is Flying (FFT)
Problem DescriptionJRY wants to drag racing along a long road. There are n sections on the road, the ...
- 借One-Class-SVM回顾SMO在SVM中的数学推导--记录毕业论文5
上篇记录了一些决策树算法,这篇是借OC-SVM填回SMO在SVM中的数学推导这个坑. 参考文献: http://research.microsoft.com/pubs/69644/tr-98-14.p ...
- 关于不同进制数之间转换的数学推导【Written By KillerLegend】
关于不同进制数之间转换的数学推导 涉及范围:正整数范围内二进制(Binary),八进制(Octonary),十进制(Decimal),十六进制(hexadecimal)之间的转换 数的进制有多种,比如 ...
- UVA - 10014 - Simple calculations (经典的数学推导题!!)
UVA - 10014 Simple calculations Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & ...
- 『sumdiv 数学推导 分治』
sumdiv(POJ 1845) Description 给定两个自然数A和B,S为A^B的所有正整数约数和,编程输出S mod 9901的结果. Input Format 只有一行,两个用空格隔开的 ...
- LDA-线性判别分析(二)Two-classes 情形的数学推导
本来是要调研 Latent Dirichlet Allocation 的那个 LDA 的, 没想到查到很多关于 Linear Discriminant Analysis 这个 LDA 的资料.初步看了 ...
- leetcode 343. Integer Break(dp或数学推导)
Given a positive integer n, break it into the sum of at least two positive integers and maximize the ...
- ZOJ3329(数学推导+期望递推)
要点: 1.期望的套路,要求n以上的期望,则设dp[i]为i分距离终点的期望步数,则终点dp值为0,答案是dp[0]. 2.此题主要在于数学推导,一方面是要写出dp[i] = 什么,虽然一大串但是思维 ...
- [国家集训队]整数的lqp拆分 数学推导 打表找规律
题解: 考场上靠打表找规律切的题,不过严谨的数学推导才是本题精妙所在:求:$\sum\prod_{i=1}^{m}F_{a{i}}$ 设 $f(i)$ 为 $N=i$ 时的答案,$F_{i}$ 为斐波 ...
随机推荐
- NBU基本常用命令
Veritas常用命令: 1. 查看当有运行的任务 bpdbjobs –report | grep Active 2. 停止任务 bpdbjobs –cancel PID (包括主任务和子任务) 3. ...
- 利用kvo实现列表倒计时
自己稍微记录一下,方便以后用到: 先创建一个定时器的类: #import "TimeCenter.h" @interface TimeCenter () @property (no ...
- THinkPHP 5.0 域名路由
ThinkPHP支持完整域名.子域名和IP部署的路由和绑定功能 要启用域名部署路由功能,首先需要开启: 'url_domain_deploy' => true 定义域名部署规则支持两种方式:动态 ...
- Bootstrap 附加导航(Affix)插件
bootstrap 附加导航(Affix)插件允许某个div元素固定到页面中的某个位置.您可以打开或关闭使用该插件之间进行切换 后续再写
- 关于小程序button控件上下边框的显示和隐藏问题
问题: 小程序的button控件上下有一条淡灰色的边框,在空件上加上了样式 border:(none/0); 都没办法让button上下的的边框隐藏: 代码如下 <button class=&q ...
- GIT 团队协作快速入门使用
GIT使用: 1.本地新建一个文件夹 git init 2.克隆远程仓库 git clone git@xxxxx.git 3.本地创建一个dev分支 (前提是服务器端已经创建好有 DEV 分支) gi ...
- SAP增强Enhancement
第一代:基于源码增强(子过程subroutine) 第一代增强基于源代码,是SAP提供的一个空代码的子过程.在这个子过程中用户可以添加自己的代码,控制自己的需求.这类增强集中在一些文件名倒数第二个字符 ...
- JZOJ 4757. 树上摩托
Description Sherco是一位经验丰富的魔♂法师.Sherco在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树.他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他的 ...
- 南阳 ACM16 矩形嵌套 动态规划
矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c, ...
- tomcat内存泄漏存入dump文件
很多tomcat进程退出(或者进程假死),都是由于频繁的抛出OutOfMemeoryError导致的. 为了让tomcat退出前或者发生OutOfMemeoryError时自动dump堆栈信息,方便事 ...