抵下唇峰 触碰刀锋
卸行装 归顺平庸
再异口同声唱 那告别曲
逝去的一身葱茏
当场写了个很蛋疼的写法,总之注意到序列必须以 A , B , A ⊕ B A, B, A\oplus B A,B,A⊕B 为循环节就基本明白了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = 100010;
int n;
int a[N], b[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
if (count(a + 1, a + n + 1, 0) == n) {
puts("Yes");
return 0;
}
if (n % 3) {
puts("No");
return 0;
}
sort(a + 1, a + n + 1);
copy(a + 1, a + n + 1, b + 1);
int m = unique(b + 1, b + n + 1) - b - 1;
if (m == 2 && b[1] == 0 && count(a + 1, a + n + 1, 0) == n / 3) {
puts("Yes");
} else if (m == 3 && (b[1] == (b[2] ^ b[3])) && count(a + 1, a + n + 1, b[1]) == n / 3 && count(a + 1, a + n + 1, b[2]) == n / 3 && count(a + 1, a + n + 1, b[3]) == n / 3)
puts("Yes");
else
puts("No");
return 0;
}
任选一个生成树做主元。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
struct E {
int v;
bool vis;
E *next, *rev;
};
const int N = 100010;
int n, m;
bool vis[N], par[N];
E* g[N];
E* adde(int u, int v) {
static E pool[N * 2], *p = pool;
++p;
p->v = v;
p->next = g[u];
g[u] = p;
return p;
}
void dfs(int u) {
vis[u] = true;
for (E* p = g[u]; p; p = p->next)
if (!p->vis) {
p->vis = p->rev->vis = true;
if (!vis[p->v]) {
dfs(p->v);
if (par[p->v]) {
printf("%d %d\n", p->v, u);
} else {
printf("%d %d\n", u, p->v);
par[u] ^= 1;
}
} else {
printf("%d %d\n", u, p->v);
par[u] ^= 1;
}
}
}
int main() {
scanf("%d%d", &n, &m);
if (m % 2) {
puts("-1");
return 0;
}
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
E *p = adde(u, v), *q = adde(v, u);
p->rev = q;
q->rev = p;
}
dfs(1);
return 0;
}
构造方法见代码。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int main() {
int n;
scanf("%d", &n);
if (!(n & (n - 1))) {
puts("No");
return 0;
}
puts("Yes");
int m = n;
printf("%d %d\n", 1 + n, 3);
if (n % 2 == 0) --m;
for (int i = 2; i < m; i += 2) {
printf("%d %d\n", i, i + 1);
printf("%d %d\n", i, 1);
printf("%d %d\n", i + n, i + 1 + n);
printf("%d %d\n", i + n + 1, 1);
}
if (n % 2 == 0) {
int x = n & -n;
int y = n - x;
printf("%d %d\n", x, n);
printf("%d %d\n", y + n + 1, n * 2);
}
return 0;
}
考虑把过程反过来,考虑计算最后移除的那个数的贡献。可以状压 DP。稍微分析一下可以发现可以 Θ ( 2 n ) \Theta(2^n) Θ(2n) 表示,此题的数据范围不需要实现得那么精细。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template <class T>
istream& operator>>(istream& is, vector<T>& v) {
for (T& x : v)
is >> x;
return is;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
if (!v.empty()) {
os << v.front();
for (int i = 1; i < v.size(); ++i)
os << ' ' << v[i];
}
return os;
}
const int N = 20;
int n;
int a[N];
map<pair<int, int>, ll> dp[N][N];
ll dfs(int l, int r, int x, int y) {
if (l + 1 == r) return 0;
auto it = dp[l][r].find(make_pair(x, y));
if (it != dp[l][r].end())
return it->second;
ll cur = 1LL << 60;
for (int i = l + 1; i < r; ++i)
cur = min(cur, dfs(l, i, x, x + y) + dfs(i, r, x + y, y) + a[i] * (ll)(x + y));
return dp[l][r][make_pair(x, y)] = cur;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
cout << (dfs(1, n, 1, 1) + a[1] + a[n]) << '\n';
return 0;
}
对于 k k k 是偶数的情况分别 DP 即可。剩下的情况可以发现对于任何一个 d ≥ 1 d\ge 1 d≥1,如果有一个长为 2 d + 1 2d + 1 2d+1 的连续段都被扣掉了,那么两边再各一个有一个被扣掉,对称部分总共不能达到 k k k,对这个前面的连续段向后造成的约束进行 DP 可以发现奇偶部分最多一个需要限制。
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template <class T>
istream& operator>>(istream& is, vector<T>& v) {
for (T& x : v)
is >> x;
return is;
}
ostream& operator<<(ostream& os, const pair<char, int>& unit) {
return os << unit.first << "^" << unit.second;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
if (!v.empty()) {
os << v.front();
for (int i = 1; i < v.size(); ++i)
os << ' ' << v[i];
}
return os;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k, M;
cin >> n >> k >> M;
function<int(int)> norm = [&](int x) { return x >= M ? x - M : x; };
function<void(int&, int)> add = [&](int& x, int y) {
(x += y) >= M ? x -= M : 0;
};
function<void(int&, int)> sub = [&](int& x, int y) {
(x -= y) < 0 ? x += M : 0;
};
if (k % 2 == 0) {
function<vi(int, int)> easy = [&](int n, int k) {
vi dp(n + 2);
dp[0] = 1;
for (int i = 1; i <= n + 1; ++i)
for (int j = 1; j <= k + 1 && j <= i; ++j)
add(dp[i], dp[i - j]);
dp.erase(dp.begin());
return dp;
};
vi need = easy((n + 1) / 2, k / 2);
cout << need[n / 2] * (ll)need[(n + 1) / 2] % M;
} else {
int nn = n / 2 + 1;
static int dp[80][80][160], newdp[80][80][160];
dp[0][0][0] = 1;
const int INF = 1 << 30;
static int glt[80][80];
function<int(int, int)> gl = [&](int a, int b) {
a = min(a, k / 2 + 2);
if ((b - a + 1) * 2 < k - a * 2 + 3 || a <= 0)
return INF;
return (k - a * 2 + 3) / 2 - 1;
};
for (int i = 0; i <= nn; ++i)
for (int j = 0; j <= nn; ++j) {
if (i >= k / 2 + 2 && j >= k / 2 + 1) continue;
glt[j + 1][i] = gl(j + 1, i);
}
for (int rep = 0; rep < n; ++rep) {
memset(newdp, 0, sizeof(newdp));
for (int i = 0; i <= nn; ++i)
for (int j = 0; j <= nn; ++j) {
if (i >= k / 2 + 2 && j >= k / 2 + 1) continue;
add(newdp[0][i][0], dp[i][j][0]);
int v = glt[j + 1][i];
if (j < k / 2 + 1 || i < k / 2 + 1)
add(newdp[j + 1][i][v == INF ? 0 : ((v + 1) << 1)], dp[i][j][0]);
add(newdp[0][i][0], dp[i][j][2]);
for (int l = 1; l <= nn; ++l) {
add(newdp[0][i][0], dp[i][j][(l + 1) << 1]);
if (j < k / 2 + 1 || i < k / 2 + 1)
add(newdp[j + 1][i][(l - 1) << 1 | 1], dp[i][j][(l + 1) << 1]);
}
for (int l = 0; l <= nn; ++l) {
add(newdp[0][i][(l + 1) << 1], dp[i][j][l << 1 | 1]);
if (j < k / 2 + 1 || i < k / 2 + 1) {
add(newdp[j + 1][i][(min(glt[j + 1][i], l) + 1) << 1], dp[i][j][l << 1 | 1]);
}
}
}
memcpy(dp, newdp, sizeof(dp));
}
int ans = 0;
for (int i = 0; i <= nn; ++i)
for (int j = 0; j <= nn; ++j)
for (int l = 0; l <= n + 5; ++l)
add(ans, dp[i][j][l]);
cout << ans;
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
考虑对每个 hist 枚举情况,发现重复的必然是一个点被本行和本列的 hist 抢夺,我们强制规定一个竖直的 hist 顶到的位置下方不能恰好是横向的 hist 顶到的。这样反而考虑每个横着的 hist 有几个位置被约束,易列生成函数
N ! [ x N ] ( ( N + 1 ) + ( N + 1 − 1 ) x + N + 1 − 2 2 ! x 2 + ⋯ + x N N ! ) M ( 1 + x + x 2 2 ! + ⋯ + x N N ) N![x^N]((N + 1) + (N + 1 - 1)x + \frac{N + 1 - 2}{2!}x^2 + \cdots + \frac{x^N}{N!})^M (1 + x + \frac{x^2}{2!} + \cdots + \frac{x^N}{N}) N![xN]((N+1)+(N+1−1)x+2!N+1−2x2+⋯+N!xN)M(1+x+2!x2+⋯+NxN)
易见把每个多项式拓展为无限形式更简单,这个分明就是
N ! [ x N ] ( ( N + 1 ) − x ) M e ( M + 1 ) x N![x^N] ((N + 1) - x)^M \mathrm{e}^{(M+1)x} N![xN]((N+1)−x)Me(M+1)x
于是预处理阶乘和幂即可计算。
#include
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template <class T>
istream& operator>>(istream& is, vector<T>& v) {
for (T& x : v)
is >> x;
return is;
}
ostream& operator<<(ostream& os, const pair<char, int>& unit) {
return os << unit.first << "^" << unit.second;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& v) {
if (!v.empty()) {
os << v.front();
for (int i = 1; i < v.size(); ++i)
os << ' ' << v[i];
}
return os;
}
const int N = 500010, P = 998244353;
int n, m;
int inv[N], ifac[N], fac[N], pw[N], qw[N];
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
if (n < m) swap(n, m);
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = -(P / i) * (ll)inv[P % i] % P + P;
ifac[0] = 1;
for (int i = 1; i <= n; ++i)
ifac[i] = ifac[i - 1] * (ll)inv[i] % P;
fac[0] = 1;
for (int i = 1; i <= n; ++i)
fac[i] = fac[i - 1] * (ll)i % P;
pw[0] = 1;
for (int i = 1; i <= m; ++i)
pw[i] = pw[i - 1] * (n + 1LL) % P;
qw[0] = 1;
for (int i = 1; i <= n; ++i)
qw[i] = qw[i - 1] * (m + 1LL) % P;
int ans = 0;
for (int i = 0; i <= m; ++i) {
int res = ((i & 1) ? (P - 1) : 1) * (ll)pw[m - i] % P * ifac[i] % P * ifac[m - i] % P * qw[n - i] % P * ifac[n - i] % P;
ans = (ans + res) % P;
}
ans = ans * (ll)fac[n] % P * fac[m] % P;
cout << ans;
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}