mns 1118
A
同步率竟然高达个位数 /kk。看来是没救了,这么简单的 dp 都没有想出来。
B
这有蓝?这有蓝?这有蓝?这有蓝?这有蓝?这有蓝?这有蓝?这有蓝?
前置知识
本文假设你有 小学二年级 高三水平,要求你知道:
- 导数的概念与基本性质
题意
给你两个\(m\) 次多项式 \(F\)、\(G\),每一次同时:
- \(F \leftarrow G - G'\)
- \(G \leftarrow F + F'\)
做 \(n\) 次,求做完之后的 \(F\) 和 \(G\)。
解法
众所周知,看到这种大数学题,我们应该 找 规 律。
考虑从 \(F\) 开始变换:
\(F_0 = F\)
\(G_1 = F - F'\)
\(F_2 = G_1 + G_1' = F - F' + F' - F'' = F - F''\)
\(G_3 = F_2 - F_2' = F - F' - F'' + F'''\)
\(F_4 = G_3 + G_3' = F - F' - F'' + F''' + F' - F'' - F''' + F'''' = F - 2F'' + F''''\)
容易瞪出 \(F_{2n} =\)
\[\sum \limits_{i = 0}^n (-1)^i F^{(2i)} \binom{n}{i}
\]
证明:
其中 \(F^{(n)}\) 为 \(F\) 的 \(n\) 阶导数 (如果你连这都不知道建议小学二年级重修)。
考虑把 F 作为自变量而把求导的次数当作次数,这样我们就得到了一个新的多项式。如上所示,每两次操作就是乘上 \(1 - x^2\)。所以直接展开 \((1 - x^2)^n\) 就可以得到这个结论了。
实现得小心一点是可以做到 \(O(m^2)\) 的。
//#define DEBUG
#include <bits/stdc++.h>
#ifdef DEBUG
#include <windows.h>
#endif
#define int ll
#define ctz __builtin_ctzll
#define popc __builtin_popcountll
#define lowbit(x) ((x) & -(x))
#define ct1(x) ctz((x) + 1)
using namespace std;
using ll = long long;
const int kMod = int(1e9) + 7, kInf = 0x3f3f3f3f3f3f3f3f;
template<class T>T read(istream &is = cin) {
T x;
is >> x;
return x;
}
int readInt(istream &is = cin) {return read<int>(is);}
template<typename T>
T qpow(T x, T y, T k = 0) {
if (x == 0 && y == 0) return k;
if (x == 0) return 0;
x %= kMod;
T res = 1;
while(y) {
if (y & 1) res = 1ll * res * x % kMod;
x = 1ll * x * x % kMod;
y >>= 1;
}
return res;
}
int qinv(int x) {return qpow(x, kMod - 2);}
random_device rd;
mt19937_64 mt(rd());
int n, m, inv[20020];
vector<int> f, g, ff, gg;
// 注意由于 n 可以特别大,这里是不能预处理组合数的,求组合数看下面
void precal() {
for(int i = 1; i <= 20000; i++) inv[i] = qinv(i);
}
int C(int x, int y) {
if(x < 0 || y < 0 || x < y) return 0;
if(y == 0) return 1;
return C(x - 1, y - 1) * x % kMod * inv[y] % kMod;
}
void daoguan(vector<int> &v) {
for(int i = 0; i < int(v.size()) - 1; i++) {
v[i] = v[i + 1] * (i + 1) % kMod;
}
v.back() = 0;
}
bool fin(vector<int> &v) {
for(auto i : v) if(i) return 0;
return 1;
}
// cnt = m / 2
vector<int> FtF(vector<int> F, int cnt) {
int fl = F.size();
vector<int> res;
res.resize(fl);
for(int i = 0; i <= cnt; i++) {
if(fin(F)) break; // 求导求成 0 了就可以不做了,这样子最多导 m + 1 次
// 此处如果不这样实现,可以被轻松卡成三次方级别导致 TLE
int tx = C(cnt, i);
for(int j = 0; j < fl; j++) {
res[j] = (res[j] + kMod + (i % 2? -1 : 1) * tx * F[j] % kMod) % kMod;
}
daoguan(F);
daoguan(F);
}
return res;
}
// 处理上面的流程无法处理的边界
vector<int> FtG(vector<int> F) {
int fl = F.size();
vector<int> res = F;
daoguan(F);
for(int i = 0; i < fl; i++) {
res[i] = (res[i] + kMod - F[i]) % kMod;
}
return res;
}
vector<int> GtF(vector<int> G) {
int gl = G.size();
vector<int> res = G;
daoguan(G);
for(int i = 0; i < gl; i++) {
res[i] = (res[i] + G[i]) % kMod;
}
return res;
}
signed main() {
#ifndef DEBUG
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
precal();
cin >> n >> m;
f.resize(m + 1), g.resize(m + 1);
for(int i = 0; i <= m; i++) cin >> f[i];
for(int i = 0; i <= m; i++) cin >> g[i];
f = FtF(f, n / 2);
if(n % 2) gg = FtG(f);
else ff = f;
g = GtF(g); // 我懒得再推一遍了
g = FtF(g, (n - 1) / 2);
if((n - 1) % 2) gg = FtG(g);
else ff = g;
for(auto i : ff) cout << i << ' ';
cout << '\n';
for(auto i : gg) cout << i << ' ';
cout << '\n';
return 0;
}
C
场上没想出最优策略,场后看了题解醍醐灌顶,哎。

浙公网安备 33010602011771号