He is Flying
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 91 Accepted Submission(s): 25
For each testcase, the first line contains one integer n . The second line contains n non-negative integers, which mean the length of every section. If we denote the total length of all the sections as s , we can guarantee that 0≤s≤50000 and 1≤n≤100000 .
2 3 1 2 3 4 0 1 2 3
0 1 1 3 0 2 3 1 3 1 6 0 2 7
给一个数组有N个数字,每个数字都大于等于0,所有数字相加不大于50000, 对于区间[l,r]如果区间点数和为S‘,那么S'的值加上r-l+1。
令sum为所有数字的总和,对(N+1)*N/2个区间进行处理计算S'和增加对应的值,最后输出0到sum的每个数的值。
分析:
普通的做法要N*N的,枚举所有的区间。但是数组太大会超时的。
由于sum <= 50000考虑构造母函数进行求解 用Si表示前i个数字的前缀和。构造如下多项式,对于计算的结果A*X^Si表示区间和为Si能够得到值为A
会fft的应该就会懂这个多项式的意义(所以不多说)。
用X^Si * X*-Sj 得到的就是区间[j+1,i]的区间和,带上系数i,则表示区间长度为i。但是我们实际要得到的是i-j的值,所以第二个乘法的目的就是减去这个j。
最后0的情况特殊处理即可。FFT用double可能精度不够用long double好。标程用的是整数进行计算的。看不懂。我的模板用long double 就行了。在hdu上要用g++提交,不然也是会wa的。标程也是要用g++提交,不然就T啦。
还要注意:
负数次幂要变成整数次幂,把sum算出来,每个负数次幂加上一个sum即可。
在每个乘法中第二个括号内,要添加一个X^0的数,表示可以选着区间[1,x]否则可能算不出[1,x]的结果(x表示>=1,<=N)的数字
直接贴代码:
我的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define ld long double
struct Complex{
ld real;
ld imag;
Complex (){}
Complex(ld the){
real = cos(the);
imag = sin(the);
}
Complex(ld a,ld b){
real = a;
imag = b;
}
};
Complex operator + (Complex a,Complex b){
return Complex(a.real+b.real,a.imag+b.imag);
}
Complex operator - (Complex a,Complex b){
return Complex(a.real-b.real,a.imag-b.imag);
}
Complex operator * (Complex a,Complex b){
return Complex(a.real*b.real-a.imag*b.imag,a.imag*b.real+a.real*b.imag);
}
#define maxn 300000
ld pi2 = 2*acos(-1.0);
void fft(Complex* A,int len, int ref){
//A[rev[k]] = ak 系数向量转置
int bitn = log2(len);
int i,j,k;
for(i = 0;i < len; i++){
k = 0;
for( j = 0;j < bitn; j++){
k = (k<<1);
if(i&(1<<j))
k |= 1;
}
if(k > i)
swap(A[i],A[k]);
}
//fft计算得到点值
Complex wm,w,t,u;
for(int m = 2,f=1; m <= len; m<<=1,f<<=1){
wm = Complex(ref*pi2/m);
for( k = 0;k < len; k += m){
w = Complex(1.0,0);
for( j = k; j < k+f; j++){
t = w*A[j+f];
u = A[j];
A[j] = u+t;
A[j+f] = u-t;
w = w*wm;
}
}
}
if(ref == -1){
for( i = 0;i < len; i++){
A[i].real = A[i].real/len;
}
}
}
Complex a1[maxn];
Complex a2[maxn];
int num[maxn];
int sum[maxn];
ll ans[maxn];
ll snum[maxn];
int main(){
int t,n;
//freopen("h.in","r",stdin);
//freopen("hh.out","w",stdout);
scanf("%d",&t);
snum[0] = 0;
for(ll i = 1; i <= 100000; i++)
snum[i] = snum[i-1] + i*(i+1)/2;
while(t--){
scanf("%d",&n);
for(int i = 0;i < n; i++)
scanf("%d",&num[i]);
sum[0] = num[0];
for(int i = 1;i < n; i++)
sum[i] = sum[i-1] + num[i];
ll p = 0 ,res = 0,lnum = 0;
for(int i = 0;i < n; i++){
if(num[i] == 0)
p++;
else {
res += snum[p];
p = 0;
}
}
res += snum[p];
printf("%I64d\n",res);
int total = sum[n-1];
int total2 = total*2;
int len = 1;
while(len <= total2) len*=2;
memset(a1,0,sizeof(a1));
memset(a2,0,sizeof(a2));
for(int i = 0; i < n; i++){
a1[sum[i]].real += i+1;
if(i != n-1)
a2[total-sum[i]].real += 1;
}
a2[total].real += 1;
fft(a1,len,1);
fft(a2,len,1);
for(int i = 0;i <= len; i++)
a1[i] = a1[i]*a2[i];
fft(a1,len,-1);
for(int i = 0;i <= len; i++)
ans[i] = (ll)(a1[i].real+0.5);
memset(a1,0,sizeof(a1));
memset(a2,0,sizeof(a2));
for(int i = 0;i < n; i++){
a1[sum[i]].real += 1;
if(i != n-1)
a2[total-sum[i]].real += i+1;
}
fft(a1,len,1);
fft(a2,len,1);
for(int i = 0;i <= len; i++)
a1[i] = a1[i]*a2[i];
fft(a1,len,-1);
for(int i = 0;i <= len; i++)
ans[i] -= (ll)(a1[i].real+0.5);
for(int i = total+1;i <= total2; i++)
printf("%I64d\n",ans[i]);
}
return 0;
}
#include <cstdio>
#include <string.h>
using namespace std;
#define P 50000000001507329LL
#define G 3
int T;
int n, s[110000];
long long ans[140000], a[140000], b[140000], c[140000], x[140000], w[140000];
long long pu[110000];
int nn;
long long Mul(long long x, long long y) {
return (x*y-(long long)(x/(long double)P*y+1e-3)*P+P)%P;
}
long long Pow(long long x, long long y) {
long long i, ans = 1;
for (i = 1; i <= y; i *= 2, x = Mul(x, x)) if (y & i) ans = Mul(ans, x);
return ans;
}
void DFT(long long *a, int n) {
int m, i, d, p, q;
for (m = 1; (1 << m) <= n; m++){
for (i = 0; i < (n >> m); i++)
for (q = 0, d = p = i; d < n; q += (n >> m), d += (n >> (m - 1)), p += (n >> m)){
x[p] = (Mul(a[d + (n >> m)], w[q]) + a[d]) % P;
x[p + n / 2] = (Mul(a[d + (n >> m)], w[q + n / 2]) + a[d]) % P;
}
for (i = 0; i < n; i++) a[i] = x[i];
}
}
void DFT1(long long *a, int n){
int m, i, d, p, q;
for (m = 1; (1 << m) <= n; m++) {
for (i = 0; i < (n >> m); i++)
for (q = 0, d = p = i; d < n; q += (n >> m), d += (n >> (m - 1)), p += (n >> m)){
x[p] = (Mul(a[d + (n >> m)], w[n - q]) + a[d]) % P;
x[p + n / 2] = (Mul(a[d + (n >> m)], w[n / 2 - q]) + a[d]) % P;
}
for (i = 0; i < n; i++) a[i] = x[i];
}
}
void doit() {
long long S = Pow(n, P - 2);
DFT(a, n);
DFT(b, n);
for (int i = 0; i < n; i++)
c[i] = Mul(a[i], b[i]);
DFT1(c, n);
for (int i = 0; i < n; i++)
c[i] = Mul(c[i], S);
for (int i = 0; i < n; i++)
ans[i] = (ans[i] + c[i]) % P;
// for (int i = 0; i <= s[n]; i++)
// for (int j = 0; j <= s[n]; j++)
// ans[i + j] += 1LL * a[i] * b[j];
}
int main() {
//freopen("h.in", "r", stdin);
//freopen("h.out", "w", stdout);
scanf("%d", &T);
n = 131072;
for (int i = 0; i <= n; i++)
w[i] = Pow(G, (P - 1) / n * i);
s[0] = 0;
while (T--) {
scanf("%d", &nn);
for (int i = 1; i <= nn; i++)
scanf("%d", &s[i]), s[i] += s[i - 1];
memset(ans, 0, sizeof ans);
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for (int i = 1; i <= nn; i++)
a[s[i]] += i;
for (int i = 1; i <= nn; i++)
b[s[nn] - s[i - 1]]++;
doit();
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for (int i = 0; i <= 50000; i++)
a[i] = b[i] = 0;
for (int i = 1; i <= nn; i++)
a[s[i]] = (a[s[i]] + P - 1) % P;
for (int i = 1; i <= nn; i++)
b[s[nn] - s[i - 1]] += i - 1;
doit();
long long ans0 = 0;
int q, h;
for (int i = 1; i <= nn; i++)
pu[i] = pu[i - 1] + 1LL * i * (i + 1) / 2;
for (q = 1; q <= nn; q = h + 1)
if (s[q] != s[q - 1]) h = q;
else {
for (h = q; h < nn && s[h + 1] == s[q]; h++);
ans0 += pu[h - q + 1];
}
printf("%lld\n", ans0);
for (int i = 1; i <= s[nn]; i++)
printf("%lld\n", ans[i + s[nn]]);
}
}