您的位置:首页 > 其它

「6月雅礼集训 2017 Day1」看无可看

2017-06-17 20:16 381 查看
【题目大意】

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

# 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 + 10, M = 2e5 + 10;
const int mod = 99991;
const double pi = acos(-1.0);

inline int getint() {
int x = 0, f = 1; char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = 0;
ch = getchar();
}
while(isdigit(ch)) {
x = (x<<3) + (x<<1) + ch - '0';
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[2][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 = 1;
while(b) {
if(b&1) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ret;
}

ST vector<int> x[M];

# define ls (x<<1)
# define rs (x<<1|1)

namespace FFT {
ST cp w[2][M]; ST int n, lst[M];
inline void init(int _n) {
n = 1;
while(n < _n) n <<= 1;
for (RG int i=0; i<n; ++i) w[0][i] = cp(cos(pi * 2.0 / n * i), sin(pi * 2.0 / n * i)),
w[1][i] = cp(w[0][i].x, -w[0][i].y);
RG int len = 0;
while((1 << len) < n) ++len;
for (RG int i=0; i<n; ++i) {
int t = 0;
for (RG int j=0; j<len; ++j) if(i & (1 << j)) t |= (1 << (len - j - 1));
lst[i] = t;
}
}
inline void DFT(cp *a, int op) {
cp *o = w[op];
for (RG int i=0; i<n; ++i) if(i < lst[i]) swap(a[i], a[lst[i]]);
for (RG int len=2; len<=n; len <<= 1) {
int m = len>>1;
for (RG cp *p = a; p != a+n; p += len) {
for (RG int k=0; 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 == 1) for (RG int i=0; 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()) * 2;
init(m);
//        printf("%d\n", n);
for (RG int i=0; i<a.size(); ++i) u[i] = cp(a[i], 0.0);
for (RG int i=0; 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, 0); DFT(v, 0);
for (RG int i=0; i<n; ++i) u[i] = u[i] * v[i];
DFT(u, 1);
for (RG int i=0; i<K+1 && 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(1), p[x].push_back(sr[id][l]);
return ;
}
RG int mid = l+r>>1;
solve(ls, l, mid); solve(rs, mid+1, 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=1; i<=n; ++i) {
a[i] = getint();
sr[0][i] = pwr(3, a[i]);
sr[1][i] = pwr(mod-1, a[i]);
}

F0 = getint(), F1 = getint();
B = 1ll * (F0 + F1) * pwr(4, mod-2) % mod;
A = (F0 - B + mod) % mod;

id = 0;
solve(1, 1, n);

int t = 1ll * B * p[1][K] % mod;

id = 1;
solve(1, 1, n);

t += 1ll * A * p[1][K] % mod;
if(t >= mod) t -= mod;

printf("%d\n", t);

int end = clock() - beg;
cerr << end << " ms" << endl;

return 0;
}


View Code
【反思】

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

60分的思路还是很好想的

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

想到特征根分解后就很容易想到分治FFT了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: