bzoj 4332 FFT型的快速幂(需要强有力的推导公式能力)

有n个小朋友,m颗糖,你要把所有糖果分给这些小朋友。

规则第 i 个小朋友没有糖果,那么他之后的小朋友都没有糖果。、
如果一个小朋友分到了 xx 个糖果,那么的他的权值是 f(x) = ox^2 + sx + u

没有分到糖果的小朋友的权值是 1

每种方案的权值是各个小朋友权值的乘积

求出所有方案的权值和

设g(i,j)表示前i个小朋友分j个糖果的权值乘积和

很容易得到一个式子

这个显然是一个卷积用FFT就可以处理

但是问题来了 我们如何得到ans呢

  

n<=1e8  朴素的算法不太行

要想办法优化一下

然后我就被卡死了  去看了网上的各种题解

顺便拔下来了一个封装性很好的FFT板子

看推导过程的点这个   想要迅速理解的看这个

然后你就看的懂下面这个式子了

然后就可以套快速幂了

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <set>
  7 #include <iostream>
  8 #include <map>
  9 #include <stack>
 10 #include <string>
 11 #include <vector>
 12 #define  eps 1e-9
 13 #define  fi first
 14 #define  se second
 15 #define  rtl   rt<<1
 16 #define  rtr   rt<<1|1
 17 #define  bug         printf("******\n")
 18 #define  mem(a,b)    memset(a,b,sizeof(a))
 19 #define  name2str(x) #x
 20 #define  fuck(x)     cout<<#x" = "<<x<<endl
 21 #define  f(a)        a*a
 22 #define  sf(n)       scanf("%d", &n)
 23 #define  sff(a,b)    scanf("%d %d", &a, &b)
 24 #define  sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
 25 #define  sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d)
 26 #define  pf          printf
 27 #define  FRE(i,a,b)  for(i = a; i <= b; i++)
 28 #define  FREE(i,a,b) for(i = a; i >= b; i--)
 29 #define  FRL(i,a,b)  for(i = a; i < b; i++)+
 30 #define  FRLL(i,a,b) for(i = a; i > b; i--)
 31 #define  FIN         freopen("data.txt","r",stdin)
 32 #define  gcd(a,b)    __gcd(a,b)
 33 #define  lowbit(x)   x&-x
 34 #define rep(i,a,b) for(int i=a;i<b;++i)
 35 #define per(i,a,b) for(int i=a-1;i>=b;--i)
 36 using namespace std;
 37 typedef long long  LL;
 38 typedef unsigned long long ULL;
 39 int modu;
 40 namespace FFT {
 41 const double pi = acos ( -1.0 );
 42 struct cpx {
 43     double a, b;
 44     cpx ( double a = 0, double b = 0 ) : a ( a ), b ( b ) {}
 45     inline void init() {
 46         a = 0, b = 0;
 47     }
 48     inline cpx operator + ( const cpx &ano ) const {
 49         return cpx ( a + ano.a, b + ano.b );
 50     }
 51     inline cpx operator - ( const cpx &ano ) const {
 52         return cpx ( a - ano.a, b - ano.b );
 53     }
 54     inline cpx operator * ( const cpx &ano ) const {
 55         return cpx ( a * ano.a - b * ano.b, b * ano.a + a * ano.b );
 56     }
 57 };
 58 typedef cpx C;
 59 typedef vector<C> vc;
 60 typedef vector<int> vi;
 61
 62 vc a, b;
 63
 64 void DFT ( vc &a, int oper = 1 ) {
 65     int n = a.size();
 66     for ( int i = 0, j = 0; i < n; ++i ) {
 67         if ( i > j ) swap ( a[i], a[j] );
 68         for ( int l = n >> 1; ( j ^= l ) < l; l >>= 1 );
 69     }
 70     for ( int l = 1, ll = 2; l < n; l <<= 1, ll <<= 1 ) {
 71         double x = oper * pi / l;
 72         C omega = 1, omegan ( cos ( x ), sin ( x ) );
 73         for ( int k = 0; k < l; ++k, omega = omega * omegan ) {
 74             for ( int st = k; st < n; st += ll ) {
 75                 C tmp = omega * a[st + l];
 76                 a[st + l] = a[st] - tmp;
 77                 a[st] = a[st] + tmp;
 78             }
 79         }
 80     }
 81     if ( oper == -1 ) for ( int i = 0; i < n; ++i ) a[i].a /= n;
 82 }
 83
 84 vi& operator * ( const vi &v1, const vi &v2 ) {
 85     int s = 1, ss = ( int ) v1.size() + ( int ) v2.size();
 86     while ( s < ss ) s <<= 1;
 87     a.resize ( s ), b.resize ( s );
 88     for ( int i = 0; i < s; ++i ) a[i].init(), b[i].init();
 89     for (  int i = 0; i < v1.size(); ++i ) a[i] = v1[i];
 90     for (  int i = 0; i < v2.size(); ++i ) b[i] = v2[i];
 91     DFT ( a ), DFT ( b );
 92     for ( int i = 0; i < s; ++i ) a[i] = a[i] * b[i];
 93     DFT ( a, -1 );
 94     static vi res;
 95     res.resize ( v1.size() );
 96     for (  int i = 0; i < v1.size(); ++i ) res[i] = ( a[i].a + 0.5 ), res[i] %= modu ;
 97     return res;
 98 }
 99
100 void operator *= ( vi &v1, const vi &v2 ) {
101     int s = 1, ss = ( int ) v1.size() + ( int ) v2.size();
102     while ( s < ss ) s <<= 1;
103     a.resize ( s ), b.resize ( s );
104     for ( int i = 0; i < s; ++i ) a[i].init(), b[i].init();
105     for (  int i = 0; i < v1.size(); ++i ) a[i] = v1[i];
106     for (  int i = 0; i < v2.size(); ++i ) b[i] = v2[i];
107     DFT ( a ), DFT ( b );
108     for ( int i = 0; i < s; ++i ) a[i] = a[i] * b[i];
109     DFT ( a, -1 );
110     for (  int i = 0; i < v1.size(); ++i ) v1[i] =  ( a[i].a + 0.5 ), v1[i] %= modu ;
111 }
112
113 void operator += ( vi &v1, const vi &v2 ) {
114     for (  int i = 0; i < v1.size(); ++i ) v1[i] = ( v1[i] + v2[i] + modu ) % modu;
115 }
116 }
117
118 using namespace FFT;
119 int m, p, n, o, s, u;
120 vi f;
121 vi expmod ( const vi&v, int b ) {
122     vi res ( v.size(), 0 ), tmp = v;
123     res[0] = 1;
124     while ( b ) {
125         if ( b & 1 ) res *= tmp;
126         tmp *= tmp;
127         b = b >> 1;
128     }
129     return res;
130 }
131 vi& solve ( int n ) {
132     static vi res, ghalf;
133     if ( n == 1 ) return res = ghalf = f;
134     solve ( n / 2 );
135     res += res * ghalf;
136     ghalf *= ghalf;
137     if ( n & 1 ) res += expmod ( f, n ), ghalf *= f;
138     return res;
139 }
140 int main() {
141     //FIN;
142     sff ( m, modu );
143     sffff ( n, o, s, u );
144     f = vi ( m + 1, 0 );
145     for ( int i = 1 ; i < m + 1 ; i++ ) f[i] = ( 1LL * o * i * i + s * i + u ) % modu;
146     vi &res = solve ( min ( n, m ) );
147     printf ( "%d\n", res[m] );
148     return 0;
149 }

原文地址:https://www.cnblogs.com/qldabiaoge/p/10447097.html

时间: 2024-10-03 19:46:14

bzoj 4332 FFT型的快速幂(需要强有力的推导公式能力)的相关文章

BZOJ 1008 越狱 题解 裸快速幂

BZOJ 1008 越狱 题解 裸快速幂 1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7887  Solved: 3372[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<

BZOJ 2510: 弱题( 矩阵快速幂 )

每进行一次, 编号为x的数对x, 和(x+1)%N都有贡献 用矩阵快速幂, O(N3logK). 注意到是循环矩阵, 可以把矩阵乘法的复杂度降到O(N2). 所以总复杂度就是O(N2logK) ---------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int maxn = 1009; int N, M, K,

BZOJ 1297: [SCOI2009]迷路 [矩阵快速幂]

Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间. Input 第一行包含两个整数,N T. 接下来有 N 行,每行一个长度为 N 的字符串. 第i行第j列为'0'表示从节点i到节点j没有边. 为'1'到'9'表示从节点i到节点j需要耗费的时间. Output 包

BZOJ 2242 [SDOI2011]计算器(快速幂+Exgcd+BSGS)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2242 [题目大意] 给出T和K 对于K=1,计算 Y^Z Mod P 的值 对于K=2,计算满足 xy≡ Z ( mod P ) 的最小非负整数 对于K=3,计算满足 Y^x ≡ Z ( mod P) 的最小非负整数 [题解] K=1情况快速幂即可 K=2情况用exgcd求解 K=3用BSGS求解 [代码] #include <cstdio> #include <cmath&

bzoj 3240 矩阵乘法+十进制快速幂

首先,构造出从f[][i]->f[][i+1]的转移矩阵a,和从f[i][m]->f[i+1][1]的转移矩阵b, 那么从f[1][1]转移到f[n][m]就是init*(a^(m-1)*b)^(n-1)*(a^(m-1)). 然后用用十进制快速幂(因为输入用的是10进制,这样就避免了高精度除法). 第一次写十进制快速幂,大概的思想是维护当前位是1-9的要乘的矩阵,然后再通过这9个矩阵自己转移. 1 /**********************************************

BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个.小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi.另外,小C认为这个问题的答案可能很大,因

BZOJ 2242 [SDOI2011]计算器 BSGS+快速幂+EXGCD

题意:链接 方法: BSGS+快速幂+EXGCD 解析: BSGS- 题解同上.. 代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MOD 140345 using namespace std; typedef long long ll; ll t,k,ans; ll y,z,p;

HDU 3221 矩阵快速幂+欧拉函数+降幂公式降幂

装载自:http://www.cnblogs.com/183zyz/archive/2012/05/11/2495401.html 题目让求一个函数调用了多少次.公式比较好推.f[n] = f[n-1]*f[n-2].然后a和b系数都是呈斐波那契规律增长的.需要先保存下来指数.但是太大了.在这里不能用小费马定理.要用降幂公式取模.(A^x)%C=A^(x%phi(C)+phi(C))%C(x>=phi(C)) Phi[C]表示不大于C的数中与C互质的数的个数,可以用欧拉函数来求. 矩阵快速幂也不

BZOJ 4332 FFT+快速幂

思路: 最裸的方程:f[i][j]=Σf[i-1][j-k]*F[k] 诶呦 这不是卷积嘛 f[i]就可以用f[i-1]卷F 求到 但是这样还是很慢 设p[i] 为Σ f[j](1<=j<=i) 发现p可以倍增推 于是  就 倍增一下  就完了... http://www.cnblogs.com/Skyminer/p/6561689.html hz神犇的题解写得非常详细.. //By SiriusRen #include <cmath> #include <cstdio>