【题目大意】

给出n个数,a[1]...a[n],称作集合S,求

aaarticlea/jpeg;base64,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" alt=" " />

其中f[i] = 2f[i-1] + 3f[i-2],给出f[0],f[1]。mod 99991

n<=100000

【题解】

暴力dp,用矩阵作为存储值,复杂度O(n^2)

# include <ctype.h>
# include <stdio.h>
# include <assert.h>
# include <iostream>
# include <string.h>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; const int N = 1e5 + , M = 2e5 + ;
const int mod = ; inline int getint() {
int x = , f = ; char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = ;
ch = getchar();
}
while(isdigit(ch)) {
x = (x<<) + (x<<) + ch - '';
ch = getchar();
}
return f ? x : -x;
} struct mat {
int n, m, a[][];
inline void set(int _n, int _m) {
n = _n, m = _m;
memset(a, , sizeof a);
}
friend mat operator * (mat a, mat b) {
mat c; c.set(a.n, b.m);
assert(a.m == b.n);
for (int i=; i<=c.n; ++i)
for (int j=; j<=c.m; ++j)
for (int k=; k<=a.m; ++k) {
c.a[i][j] += 1ll * a.a[i][k] * b.a[k][j] % mod;
if(c.a[i][j] >= mod) c.a[i][j] -= mod;
}
return c;
}
friend mat operator ^ (mat a, ll b) {
mat c; c.set(a.n, a.n);
assert(a.n == a.m);
for (int i=; i<=c.n; ++i) c.a[i][i] = ;
while(b) {
if(b&) c = c * a;
a = a * a;
b >>= ;
}
return c;
}
friend mat operator + (mat a, mat b) {
assert(a.n == b.n && a.m == b.m);
for (int i=; i<=a.n; ++i)
for (int j=; j<=a.m; ++j) {
a.a[i][j] += b.a[i][j];
if(a.a[i][j] >= mod) a.a[i][j] -= mod;
}
return a;
}
}A, T, U, g[][], e[M]; inline int f(ll n) {
if(n == ) return A.a[][];
U = (T^(n-)) * A;
return U.a[][];
} int n, K, a[M]; inline void force() {
int now = , pre = ;
for (int i=; i<=; ++i)
for (int j=; j<=n; ++j) g[i][j].set(, );
for (int i=; i<=n; ++i) {
g[now][] = g[pre][] = A;
for (int j=, jto = min(i, K); j<=jto; ++j) {
g[now][j] = g[pre][j] + (e[i] * g[pre][j-]);
// printf("%d %d %d\n", i, j, g[i][j].a[1][1]);
}
swap(pre, now);
}
printf("%d\n", g[pre][K].a[][]);
} int main() {
// freopen("see.in", "r", stdin);
// freopen("see.out", "w", stdout);
n = getint(), K = getint();
for (int i=; i<=n; ++i) a[i] = getint();
A.set(, );
T.set(, );
cin >> A.a[][] >> A.a[][];
T.a[][] = , T.a[][] = , T.a[][] = , T.a[][] = ;
for (int i=; i<=n; ++i) e[i] = (T^a[i]);
force();
return ;
}
/*
4 2
1 2 1 3
1 1 20 10
125 3162 3261 152 376 238 462 4382 376 4972 16 1872 463 9878 688 308 125 236 3526 543
1223 3412
*/

根据特征根那套理论,设f[i] = x^i,那么有x^2-2x-3=0,解出x=3和x=-1两个根。

那么f[i] = a*3^i + b*(-1)^i

带入f[0],f[1]可以解出a,b(取模意义下)

然后f[a1+a2+...+ak] = a * 3^a1 * 3^a2 * ... * 3^ak + b * (-1)^a1 * (-1)*a2 * ... * (-1)^ak。(取模意义下)

明显3和-1互不干扰,所以分开来算。

n个数选出k个,提示了我们生成函数。

对于每个a[i],构造多项式(1+base^a[i] * x),base为3/-1.

然后答案就是(1+base^a[1]) * (1+base^a[2]) * ... * (1+base^a[n])

这个东西可以分治FFT解决,O(nlogn^2n)

做两遍分治FFT即可解决问题。

# include <math.h>
# include <vector>
# include <stdio.h>
# include <iostream>
# include <string.h>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; # define RG register
# define ST static const int N = 1e5 + , M = 2e5 + ;
const int mod = ;
const double pi = acos(-1.0); inline int getint() {
int x = , f = ; char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = ;
ch = getchar();
}
while(isdigit(ch)) {
x = (x<<) + (x<<) + ch - '';
ch = getchar();
}
return f ? x : -x;
} // x^2 - 2x - 3 = 0
// x1 = -1, x2 = 3
// f(x) = A * (-1)^x + B * 3^x
// f(x) = A * (-1)^{a1+a2+...+ak} + B * 3^{a1+a2+...+ak}
// f(x) = A * (-1)^{a1} * (-1)^{a2} * ... + B * 3^{a1} * 3^{a2} * ... // (1 + 3^a) ST int n, K, a[M], sr[][M];
ST int A, B, F0, F1; struct cp {
double x, y;
cp() {}
cp(double x, double y) : x(x), y(y) {}
friend cp operator + (cp a, cp b) {
return cp(a.x+b.x, a.y+b.y);
}
friend cp operator - (cp a, cp b) {
return cp(a.x-b.x, a.y-b.y);
}
friend cp operator * (cp a, cp b) {
return cp(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x);
}
};
ST cp u[M], v[M]; inline int pwr(int a, int b) {
int ret = ;
while(b) {
if(b&) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
b >>= ;
}
return ret;
} ST int p[M]; namespace FFT {
ST cp w[][M]; ST int n, lst[M];
inline void init(int _n) {
n = ;
while(n < _n) n <<= ;
for (RG int i=; i<n; ++i) w[][i] = cp(cos(pi * 2.0 / n * i), sin(pi * 2.0 / n * i)),
w[][i] = cp(w[][i].x, -w[][i].y);
RG int len = ;
while(( << len) < n) ++len;
for (RG int i=; i<n; ++i) {
int t = ;
for (RG int j=; j<len; ++j) if(i & ( << j)) t |= ( << (len - j - ));
lst[i] = t;
}
}
inline void DFT(cp *a, int op) {
cp *o = w[op];
for (RG int i=; i<n; ++i) if(i < lst[i]) swap(a[i], a[lst[i]]);
for (RG int len=; len<=n; len <<= ) {
int m = len>>;
for (RG cp *p = a; p != a+n; p += len) {
for (RG int k=; k<m; ++k) {
cp t = o[n/len*k] * p[k+m];
p[k+m] = p[k] - t;
p[k] = p[k] + t;
}
}
}
if(op == ) for (RG int i=; i<n; ++i) a[i].x /= (double)n;
}
inline void merge(int l, int mid, int r) {
int m = r-l+;
init(m);
// printf("%d\n", n);
u[] = cp(1.0, 0.0), v[] = cp(1.0, 0.0);
for (RG int i=; i<=mid-l+; ++i) u[i] = cp(p[i+l-], 0.0);
for (RG int i=; i<=r-mid; ++i) v[i] = cp(p[i+mid], 0.0);
for (RG int i=mid-l+; i<n; ++i) u[i] = cp(0.0, 0.0);
for (RG int i=r-mid+; i<n; ++i) v[i] = cp(0.0, 0.0);
DFT(u, ); DFT(v, );
for (RG int i=; i<n; ++i) u[i] = u[i] * v[i];
DFT(u, );
for (RG int i=; i<m; ++i) p[l+i-] = ((ll)(u[i].x + 0.5)) % mod;
}
} int id;
inline void solve(int l, int r) {
if(l == r) {
p[l] = sr[id][l];
return ;
}
RG int mid = l+r>>;
solve(l, mid); solve(mid+, r);
FFT::merge(l, mid, r);
// printf("l = %d, r = %d\n", l, r);
// for (int i=0; i<p[x].size(); ++i) printf("%d ", p[x][i]);
// puts("");
} int main() {
// freopen("see.in", "r", stdin);
// freopen("see.out", "w", stdout);
n = getint(), K = getint();
for (RG int i=; i<=n; ++i) {
a[i] = getint();
sr[][i] = pwr(, a[i]);
sr[][i] = pwr(mod-, a[i]);
} F0 = getint(), F1 = getint();
B = 1ll * (F0 + F1) * pwr(, mod-) % mod;
A = (F0 - B + mod) % mod; id = ;
solve(, n); int t = 1ll * B * p[K] % mod; id = ;
solve(, n); t += 1ll * A * p[K] % mod;
if(t >= mod) t -= mod; printf("%d\n", t); return ;
}

顺便贴一个被卡常的分治FFT.......

# include <math.h>
# include <vector>
# include <stdio.h>
# include <iostream>
# include <string.h>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; # define RG register
# define ST static const int N = 1e5 + , M = 2e5 + ;
const int mod = ;
const double pi = acos(-1.0); inline int getint() {
int x = , f = ; char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = ;
ch = getchar();
}
while(isdigit(ch)) {
x = (x<<) + (x<<) + ch - '';
ch = getchar();
}
return f ? x : -x;
} // x^2 - 2x - 3 = 0
// x1 = -1, x2 = 3
// f(x) = A * (-1)^x + B * 3^x
// f(x) = A * (-1)^{a1+a2+...+ak} + B * 3^{a1+a2+...+ak}
// f(x) = A * (-1)^{a1} * (-1)^{a2} * ... + B * 3^{a1} * 3^{a2} * ... // (1 + 3^a) ST int n, K, a[M], sr[][M];
ST int A, B, F0, F1; struct cp {
double x, y;
cp() {}
cp(double x, double y) : x(x), y(y) {}
friend cp operator + (cp a, cp b) {
return cp(a.x+b.x, a.y+b.y);
}
friend cp operator - (cp a, cp b) {
return cp(a.x-b.x, a.y-b.y);
}
friend cp operator * (cp a, cp b) {
return cp(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x);
}
};
ST cp u[M], v[M]; inline int pwr(int a, int b) {
int ret = ;
while(b) {
if(b&) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
b >>= ;
}
return ret;
} ST vector<int> x[M]; # define ls (x<<)
# define rs (x<<|) namespace FFT {
ST cp w[][M]; ST int n, lst[M];
inline void init(int _n) {
n = ;
while(n < _n) n <<= ;
for (RG int i=; i<n; ++i) w[][i] = cp(cos(pi * 2.0 / n * i), sin(pi * 2.0 / n * i)),
w[][i] = cp(w[][i].x, -w[][i].y);
RG int len = ;
while(( << len) < n) ++len;
for (RG int i=; i<n; ++i) {
int t = ;
for (RG int j=; j<len; ++j) if(i & ( << j)) t |= ( << (len - j - ));
lst[i] = t;
}
}
inline void DFT(cp *a, int op) {
cp *o = w[op];
for (RG int i=; i<n; ++i) if(i < lst[i]) swap(a[i], a[lst[i]]);
for (RG int len=; len<=n; len <<= ) {
int m = len>>;
for (RG cp *p = a; p != a+n; p += len) {
for (RG int k=; k<m; ++k) {
cp t = o[n/len*k] * p[k+m];
p[k+m] = p[k] - t;
p[k] = p[k] + t;
}
}
}
if(op == ) for (RG int i=; i<n; ++i) a[i].x /= (double)n;
}
inline vector<int> merge(vector<int> a, vector<int> b) {
vector<int> ret; ret.clear();
int m = max(a.size(), b.size()) * ;
init(m);
// printf("%d\n", n);
for (RG int i=; i<a.size(); ++i) u[i] = cp(a[i], 0.0);
for (RG int i=; i<b.size(); ++i) v[i] = cp(b[i], 0.0);
for (RG int i=a.size(); i<n; ++i) u[i] = cp(0.0, 0.0);
for (RG int i=b.size(); i<n; ++i) v[i] = cp(0.0, 0.0);
DFT(u, ); DFT(v, );
for (RG int i=; i<n; ++i) u[i] = u[i] * v[i];
DFT(u, );
for (RG int i=; i<K+ && i<m; ++i) ret.push_back(((ll)(u[i].x + 0.5)) % mod);
return ret;
}
} int id;
inline void solve(int x, int l, int r) {
if(l == r) {
p[x].clear(); p[x].push_back(), p[x].push_back(sr[id][l]);
return ;
}
RG int mid = l+r>>;
solve(ls, l, mid); solve(rs, mid+, r);
p[x] = FFT::merge(p[ls], p[rs]);
// printf("l = %d, r = %d\n", l, r);
// for (int i=0; i<p[x].size(); ++i) printf("%d ", p[x][i]);
// puts("");
} # include <time.h> int main() {
// freopen("see.in", "r", stdin);
// freopen("see.out", "w", stdout);
int beg = clock();
n = getint(), K = getint();
for (RG int i=; i<=n; ++i) {
a[i] = getint();
sr[][i] = pwr(, a[i]);
sr[][i] = pwr(mod-, a[i]);
} F0 = getint(), F1 = getint();
B = 1ll * (F0 + F1) * pwr(, mod-) % mod;
A = (F0 - B + mod) % mod; id = ;
solve(, , n); int t = 1ll * B * p[][K] % mod; id = ;
solve(, , n); t += 1ll * A * p[][K] % mod;
if(t >= mod) t -= mod; printf("%d\n", t); int end = clock() - beg;
cerr << end << " ms" << endl; return ;
}

【反思】

考场写了60分代码(好像因为数组没开大。。只有40...)

60分的思路还是很好想的

100分要注意到递推的性质用特征根这些来辅助解决。

想到特征根分解后就很容易想到分治FFT了

「6月雅礼集训 2017 Day1」看无可看的更多相关文章

  1. 「6月雅礼集训 2017 Day1」说无可说

    [题目大意] 给出n个字符串,求有多少组字符串之间编辑距离为1~8. n<=200,∑|S| <= 10^6 [题解] 首先找编辑距离有一个n^2的dp,由于发现只找小于等于8的,所以搜旁 ...

  2. 「6月雅礼集训 2017 Day10」quote

    [题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...

  3. 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)

    原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 | ...

  4. 「6月雅礼集训 2017 Day11」delight

    [题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...

  5. 「6月雅礼集训 2017 Day11」jump

    [题目大意] 有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中. 定义$(i,j)$的距离表示从$i ...

  6. 「6月雅礼集训 2017 Day11」tree

    [题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...

  7. 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)

    [题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...

  8. 「6月雅礼集训 2017 Day8」route

    [题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...

  9. 「6月雅礼集训 2017 Day8」gcd

    [题目大意] 定义times(a, b)表示用辗转相除计算a和b的最大公约数所需步骤. 那么有: 1. times(a, b) = times(b, a) 2. times(a, 0) = 0 3. ...

随机推荐

  1. CentOS7安装Oracle 11gR2 图文详解

    注:Oracle11gR2 X64安装 一.环境准备 安装包: 1.VMware-workstation-full-11.1.0-2496824.exe 2.CentOS-7-x86_64-DVD-1 ...

  2. BeyondCompare3 提示许可证密钥已被撤销解决方法

    今天对比文件提示 许可证密钥已被撤销:3281-0350! 找过了几个注册码还是不行. 正确简单的解决方法: 1.找到 BCState.xml 文件 ​ 2.编辑器打开,删除<TCheckFor ...

  3. 虚拟现实-VR-UE4-创建第一个C++项目——Hello word

    这部分主要是调用在C++中用代码实现在游戏界面上面输出一行文字 第一步,新建C++版本的工程文件,在4.12版本以后,在创建后,都会自动打开Vs编译器. 如下图 在VS中点击编译,等带编译,第一次等待 ...

  4. C 计算金额

    #include <stdio.h> int main(int argc, char **argv) { \\定义两个变量 a金额 z跟票面 int a=0; int z=0;\\ 输入金 ...

  5. 剑指offer-旋转数组的最小数字06

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  6. Annoy解析

    Annoy是高维空间求近似最近邻的一个开源库. Annoy构建一棵二叉树,查询时间为O(logn). Annoy通过随机挑选两个点,并使用垂直于这个点的等距离超平面将集合划分为两部分. 如图所示,图中 ...

  7. Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...

  8. Unity3D - UGUI实现Tab键切换输入框、按钮(按Tab键切换高亮显示的UI)

    1.在Hierarchy面板创建能被选中的UI(Button.InputField等). 2.在Canvas上创建C#脚本 TabCutPichon. 3.编写脚本. using System.Col ...

  9. 高级C代码的汇编分析

    在windows上,常用的函数调用方式有: Pascal方式,WINAPI(_stdcall)方式 和C方式(_cdecl) _cdecl调用规则: 1,参数从右到左入堆栈 2,在函数返回后,调用者要 ...

  10. C语言100例01 PHP版(练习)

    题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 代码: for ...