HDU 5307 He is Flying【FFT】

灰太狼 2022-08-02 14:48 104阅读 0赞

题意:
有n段路,每段路长度为si,你从节点i到节点j,可以获得一个开心值j−i+1,然后问你,主人公走过了所有总长度为s的段,问你有多少开心值。
思路:
首先想到的就是类似于组合数学那样,于是就想到了母函数:

(∑ix∑si)(∑x−∑si−1)−(∑x∑si)(∑(i−1)x−∑si−1)

预处理出前缀和,用FFT做。
当然要预处理出 s=0 的结果,用 O(n) 扫描一遍就行了。
官方的题解说,FFT可能会被卡常数,但是用了long double之后就可以顺利过了
另外,负数的处理方法有几种,一种是加上一个偏移量,另一种是将整个复数数组翻转过来。

  1. // whn6325689
  2. // Mr.Phoebe
  3. // http://blog.csdn.net/u013007900
  4. #include <algorithm>
  5. #include <iostream>
  6. #include <iomanip>
  7. #include <cstring>
  8. #include <climits>
  9. #include <complex>
  10. #include <fstream>
  11. #include <cassert>
  12. #include <cstdio>
  13. #include <bitset>
  14. #include <vector>
  15. #include <deque>
  16. #include <queue>
  17. #include <stack>
  18. #include <ctime>
  19. #include <set>
  20. #include <map>
  21. #include <cmath>
  22. #include <functional>
  23. #include <numeric>
  24. #pragma comment(linker, "/STACK:1024000000,1024000000")
  25. using namespace std;
  26. #define eps 1e-9
  27. #define PI acos(-1.0)
  28. #define INF 0x3f3f3f3f
  29. #define LLINF 1LL<<62
  30. #define speed std::ios::sync_with_stdio(false);
  31. typedef long long ll;
  32. typedef long double ld;
  33. typedef pair<ll, ll> pll;
  34. typedef complex<ld> point;
  35. typedef pair<int, int> pii;
  36. typedef pair<pii, int> piii;
  37. typedef vector<int> vi;
  38. #define CLR(x,y) memset(x,y,sizeof(x))
  39. #define CPY(x,y) memcpy(x,y,sizeof(x))
  40. #define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
  41. #define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))
  42. #define mp(x,y) make_pair(x,y)
  43. #define pb(x) push_back(x)
  44. #define lowbit(x) (x&(-x))
  45. #define MID(x,y) (x+((y-x)>>1))
  46. #define ls (idx<<1)
  47. #define rs (idx<<1|1)
  48. #define lson ls,l,mid
  49. #define rson rs,mid+1,r
  50. #define root 1,1,n
  51. template<class T>
  52. inline bool read(T &n)
  53. {
  54. T x = 0, tmp = 1;
  55. char c = getchar();
  56. while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
  57. if(c == EOF) return false;
  58. if(c == '-') c = getchar(), tmp = -1;
  59. while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
  60. n = x*tmp;
  61. return true;
  62. }
  63. template <class T>
  64. inline void write(T n)
  65. {
  66. if(n < 0)
  67. {
  68. putchar('-');
  69. n = -n;
  70. }
  71. int len = 0,data[20];
  72. while(n)
  73. {
  74. data[len++] = n%10;
  75. n /= 10;
  76. }
  77. if(!len) data[len++] = 0;
  78. while(len--) putchar(data[len]+48);
  79. }
  80. //-----------------------------------
  81. const int MAXN=50010;
  82. const ld pi=acosl(-1.0);
  83. struct Complex
  84. {
  85. ld r,i;
  86. Complex(){}
  87. Complex(ld r ,ld i):r(r),i(i) {}
  88. Complex operator + (const Complex& t) const
  89. {
  90. return Complex(r+t.r,i+t.i) ;
  91. }
  92. Complex operator - (const Complex& t) const
  93. {
  94. return Complex(r-t.r,i-t.i);
  95. }
  96. Complex operator * (const Complex& t) const
  97. {
  98. return Complex(r*t.r-i*t.i,r*t.i+i*t.r);
  99. }
  100. }las[MAXN*5],pre[MAXN*5],c[MAXN*5];
  101. void FFT(Complex y[],int n,int rev)//rev=-1表示逆变换
  102. {
  103. for(int i=1,j,k,t; i<n; i++) //进行蝶型变换
  104. {
  105. for(j=0,k=n>>1,t=i; k; k>>=1,t>>=1) j=j<<1|t&1;
  106. if(i<j ) swap(y[i],y[j]);
  107. }
  108. for ( int s = 2 , ds = 1 ; s <= n ; ds = s , s <<= 1 )
  109. {
  110. Complex wn=Complex(cosl(rev*2*pi/s),sinl(rev*2*pi/s)),w=Complex(1,0),t;
  111. for(int k=0; k<ds; k++,w=w*wn)
  112. {
  113. for(int i=k; i<n; i+=s)
  114. {
  115. y[i+ds]=y[i]-(t=w*y[i+ds]);
  116. y[i]=y[i]+t;
  117. }
  118. }
  119. }
  120. if(rev==-1) for(int i=0; i<n; i++) y[i].r/=n;
  121. }
  122. int n;
  123. ll val[MAXN*5],ans[MAXN*5];
  124. ll pu[MAXN*5];
  125. int main()
  126. {
  127. // freopen("data.txt","r",stdin);
  128. // freopen("out.txt","w",stdout);
  129. for(int i=1;i<=MAXN*3;i++)
  130. pu[i]=pu[i-1]+1LL*i*(i+1)/2;
  131. int T,temp;
  132. read(T);
  133. while(T--)
  134. {
  135. read(n);temp=0;
  136. int L=1;CLR(ans,0);
  137. for(int i=1;i<=n;i++)
  138. {
  139. read(val[i]);
  140. val[i]+=val[i-1];
  141. }
  142. for (int q=1,h=0;q<=n;q=h+1)
  143. if(val[q]!=val[q-1]) h=q;
  144. else
  145. {
  146. for(h=q;h<n && val[h+1]==val[q];h++);
  147. ans[0]+=pu[h-q+1];
  148. }
  149. while(L<=val[n]) L<<=1;
  150. L<<=1;
  151. CLR(las,0);CLR(pre,0);CLR(c,0);
  152. for(int i=1;i<=n;i++) las[val[i]].r+=i;
  153. for(int i=1;i<=n;i++) pre[-val[i-1]+val[n]].r+=1.0;
  154. FFT(las,L,1);FFT(pre,L,1);
  155. for(int i=0;i<L;i++)
  156. c[i]=las[i]*pre[i];
  157. FFT(c,L,-1);
  158. for(int i=1;i<L;i++)
  159. ans[i]+=ll(c[i].r+0.1);
  160. CLR(las,0);CLR(pre,0);CLR(c,0);
  161. for(int i=1;i<=n;i++) las[val[i]].r+=1.0;
  162. for(int i=1;i<=n;i++) pre[-val[i-1]+val[n]].r+=i-1;
  163. FFT(las,L,1);FFT(pre,L,1);
  164. for(int i=0;i<L;i++)
  165. c[i]=las[i]*pre[i];
  166. FFT(c,L,-1);
  167. for(int i=1;i<L;i++)
  168. ans[i]-=ll(c[i].r+0.1);
  169. printf("%lld\n",ans[0]);
  170. for(int i=1;i<val[n]+1;i++)
  171. printf("%lld\n",ans[i+val[n]]);
  172. }
  173. return 0;
  174. }

下面是官方的题解
用的是两个231以内的模数分别FFT,最后用中国剩余定理合并。

  1. #include <cstdio>
  2. #include <string.h>
  3. using namespace std;
  4. #define P 50000000001507329LL
  5. #define G 3
  6. int T;
  7. int n, s[110000];
  8. long long ans[140000], a[140000], b[140000], c[140000], x[140000], w[140000];
  9. long long pu[110000];
  10. int nn;
  11. long long Mul(long long x, long long y) {
  12. return (x*y-(long long)(x/(long double)P*y+1e-3)*P+P)%P;
  13. }
  14. long long Pow(long long x, long long y) {
  15. long long i, ans = 1;
  16. for (i = 1; i <= y; i *= 2, x = Mul(x, x)) if (y & i) ans = Mul(ans, x);
  17. return ans;
  18. }
  19. void DFT(long long *a, int n) {
  20. int m, i, d, p, q;
  21. for (m = 1; (1 << m) <= n; m++){
  22. for (i = 0; i < (n >> m); i++)
  23. for (q = 0, d = p = i; d < n; q += (n >> m), d += (n >> (m - 1)), p += (n >> m)){
  24. x[p] = (Mul(a[d + (n >> m)], w[q]) + a[d]) % P;
  25. x[p + n / 2] = (Mul(a[d + (n >> m)], w[q + n / 2]) + a[d]) % P;
  26. }
  27. for (i = 0; i < n; i++) a[i] = x[i];
  28. }
  29. }
  30. void DFT1(long long *a, int n){
  31. int m, i, d, p, q;
  32. for (m = 1; (1 << m) <= n; m++) {
  33. for (i = 0; i < (n >> m); i++)
  34. for (q = 0, d = p = i; d < n; q += (n >> m), d += (n >> (m - 1)), p += (n >> m)){
  35. x[p] = (Mul(a[d + (n >> m)], w[n - q]) + a[d]) % P;
  36. x[p + n / 2] = (Mul(a[d + (n >> m)], w[n / 2 - q]) + a[d]) % P;
  37. }
  38. for (i = 0; i < n; i++) a[i] = x[i];
  39. }
  40. }
  41. void doit() {
  42. long long S = Pow(n, P - 2);
  43. DFT(a, n);
  44. DFT(b, n);
  45. for (int i = 0; i < n; i++)
  46. c[i] = Mul(a[i], b[i]);
  47. DFT1(c, n);
  48. for (int i = 0; i < n; i++)
  49. c[i] = Mul(c[i], S);
  50. for (int i = 0; i < n; i++)
  51. ans[i] = (ans[i] + c[i]) % P;
  52. // for (int i = 0; i <= s[n]; i++)
  53. // for (int j = 0; j <= s[n]; j++)
  54. // ans[i + j] += 1LL * a[i] * b[j];
  55. }
  56. int main() {
  57. // freopen("a.in", "r", stdin);
  58. // freopen("std.out", "w", stdout);
  59. scanf("%d", &T);
  60. n = 131072;
  61. for (int i = 0; i <= n; i++)
  62. w[i] = Pow(G, (P - 1) / n * i);
  63. while (T--) {
  64. scanf("%d", &nn);
  65. for (int i = 1; i <= nn; i++)
  66. scanf("%d", &s[i]), s[i] += s[i - 1];
  67. memset(ans, 0, sizeof ans);
  68. memset(a, 0, sizeof a);
  69. memset(b, 0, sizeof b);
  70. for (int i = 1; i <= nn; i++)
  71. a[s[i]] += i;
  72. for (int i = 1; i <= nn; i++)
  73. b[s[nn] - s[i - 1]]++;
  74. doit();
  75. memset(a, 0, sizeof a);
  76. memset(b, 0, sizeof b);
  77. for (int i = 0; i <= 50000; i++)
  78. a[i] = b[i] = 0;
  79. for (int i = 1; i <= nn; i++)
  80. a[s[i]] = (a[s[i]] + P - 1) % P;
  81. for (int i = 1; i <= nn; i++)
  82. b[s[nn] - s[i - 1]] += i - 1;
  83. doit();
  84. long long ans0 = 0;
  85. int q, h;
  86. for (int i = 1; i <= nn; i++)
  87. pu[i] = pu[i - 1] + 1LL * i * (i + 1) / 2;
  88. for (q = 1; q <= nn; q = h + 1)
  89. if (s[q] != s[q - 1]) h = q;
  90. else {
  91. for (h = q; h < nn && s[h + 1] == s[q]; h++);
  92. ans0 += pu[h - q + 1];
  93. }
  94. printf("%lld\n", ans0);
  95. for (int i = 1; i <= s[nn]; i++)
  96. printf("%lld\n", ans[i + s[nn]]);
  97. }
  98. }

发表评论

表情:
评论列表 (有 0 条评论,104人围观)

还没有评论,来说两句吧...

相关阅读

    相关 论ACM ICPC_Ruins He

    这段时间老是有许多新人向我问到ACM相关的问题。比如它与工作的关系,对我以后的工作到底有没有帮助?还比如说第二年的训练计划应该是什么样的?还有的孩子问到,我寒假玩儿的一个寒假,

    相关 HDU 5307 He is Flying【FFT】

    题意: 有n段路,每段路长度为si,你从节点i到节点j,可以获得一个开心值j−i\+1,然后问你,主人公走过了所有总长度为s的段,问你有多少开心值。 思路: 首先想