题意
x(n)=x(n)h(n)[u(n)-u(n-N-1)],求x(N)。N为10^5,表示卷积。
思路
不要一看这个式子就以为h(n)是delta(n),如果h(n)=delta(n)则满足这个式子,但不能逆向推导。这里h(0)=0,也就是说每个x(n)是由前面的结果得出的。不能直接快速傅里叶变换求卷积。
既然x(n)是强制在线一个一个输入的,显然是数字信号处理中的分段流水处理,有重叠相加法和重叠保留法。但是输入段的有效长度为1,肯定会超时,重叠保留法在此题就没有优化空间了。
考虑重叠相加法,如果加长每次运算的长度,那么输出就是多节运算的叠加。考虑如何能减少叠加的次数。当然接着fft的分治思路想到cdq分治,不固定输入长度,而用二分法动态决定输入序列的长度,树状划分,重叠相加,就可以在O(NlogN)的时间解决了。
AC代码 C++
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define MAXN (100005 << 1)
#define MOD 313
namespace FFT
{
const int FFT_N = MAXN;
const int FFT_MOD = MOD;
const double pi = acos(-1.0);
int pos[FFT_N];
struct comp{
double r,i;
comp(double _r = 0, double _i =0): r(_r), i(_i){}
comp operator + (const comp& x){return comp(r + x.r, i + x.i);}
comp operator - (const comp& x){return comp(r - x.r, i - x.i);}
comp operator * (const comp& x){return comp(r * x.r - i * x.i, i * x.r + r * x.i);}
comp conj(){return comp(r, -i);}
}A[FFT_N], B[FFT_N];
void FFT(comp a[], int n , int t)
{
for(int i=1; i<n; i++)
if(pos[i] > i)
swap(a[i], a[pos[i]]);
for(int d = 0;(1<<d) < n ;d++)
{
int m = 1<<d, m2 = m<<1;
double o = pi*2 / m2 * t;
comp _w(cos(o), sin(o));
for(int i=0;i<n;i+=m2)
{
comp w(1,0);
for(int j=0;j<m;j++)
{
comp& A = a[i + j + m], &B = a[i+j], t = w*A;
A = B - t;
B = B + t;
w = w * _w;
}
}
}
if(t == -1)
for(int i=0; i<n; i++)
a[i].r /= n;
}
void mul(int* a, int* b, int* c,int k)
{
int i, j = __builtin_ctz(k) - 1;
for(i=0; i<k; i++)
pos[i] = pos[i>>1] >> 1 | ((i & 1) << j);
for(i =0; i<k;i++)
A[i] = comp(a[i], b[i]);
FFT(A, k , 1);
for(i=0; i<k; i++)
{
j = (k-i) & (k-1);
B[i] = (A[i] * A[i] - (A[j] * A[j]).conj() ) * comp(0, -0.25);
}
FFT(B, k, -1);
for(i=0; i<k; i++)
c[i] = (long long) (B[i].r + 0.5) % FFT_MOD;
}
}
int a[MAXN];
int b[MAXN];
int c[MAXN];
int d[MAXN];
int dp[MAXN];
void cdq(int l, int r)
{
if(l == r)
{
dp[r] = (dp[r] + a[r]) % MOD;
return;
}
int mid=l+r>>1, i, len=1;
cdq(l, mid);
while(len < r - l + 1)
len <<= 1;
for(i=0; i<len; i++)
{
b[i] = l + i > mid ? 0 : dp[l + i];
c[i] = i < r ? a[i+1] : 0;
}
FFT::mul(b, c, d, len);
for(i=mid+1; i<=r; i++)
dp[i] = (dp[i] + d[i-l-1]) % MOD;
cdq(mid+1, r);
}
int main()
{
int n, i;
while(scanf("%d", &n) && n)
{
for(i=1; i<=n; a[i++]%=MOD)
scanf("%d", a+i);
memset(dp, 0, sizeof dp);
cdq(1, n);
printf("%d\n", dp[n]);
}
return 0;
}