洛谷提高模拟赛2
凉
比赛链接 ()[https://www.luogu.org/contestnew/show/11251]
T1
显然排序后每一个豆子都在上一个的右下角
排序后组合数统计步数就可以了
知识点补充:组合数统计步数 在dx+dy步中 选dx步向下走 其余向右走
标程
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int MOD = (int)1e9 + 7;
int n, m, k, fac[MAXN], inv[MAXN];
struct Point {
int x, y;
bool operator<(const Point & rhs) const {
return x + y < rhs.x + rhs.y;
}
}P[MAXN];
int fexp(int x, int y) {
int res = 1;
for(int i = 1; i <= y; i <<= 1) {
if(i & y) res = 1LL * res * x % MOD;
x = 1LL * x * x % MOD;
}
return res;
}
void init(int n) {
fac[0] = inv[0] = 1;
for(int i = 1; i <= n; i++) {
fac[i] = 1LL * fac[i - 1] * i % MOD;
inv[i] = fexp(fac[i], MOD - 2);
}
}
int C(int n, int m) {
assert(n >= m);
return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
int main() {
scanf("%d %d %d", &n, &m, &k);
init(200000);
for(int i = 1; i <= k; i++) {
scanf("%d %d", &P[i].x, &P[i].y);
}
P[++k] = Point{1, 1};
P[++k] = Point{n, m};
sort(P + 1, P + k + 1);
int ans = 1;
for(int i = 2; i <= k; i++) {
int dx = P[i].x - P[i - 1].x;
int dy = P[i].y - P[i - 1].y;
if(dx < 0 || dy < 0) {
ans = 0;
break;
}
ans = 1LL * ans * C(dx + dy, dx) % MOD;
}
printf("%d\n", ans);
return 0;
}
T2
想到了统计不满足的 但是没有解决重叠问题
正解:树链剖分扫描线
子树dfn连续嘛
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
int n, k;
vector<int> G[MAXN];
int dfs_clock, deep[MAXN], fa[MAXN], size[MAXN];
int son[MAXN], top[MAXN], dfn[MAXN], dfm[MAXN], low[MAXN];
void dfs1(int cur, int father, int depth) {
size[cur] = 1;
fa[cur] = father;
deep[cur] = depth;
son[cur] = 0;
for(int i = 0; i < G[cur].size(); i++) {
int nx = G[cur][i];
if(nx != father) {
dfs1(nx, cur, depth + 1);
size[cur] += size[nx];
if(size[nx] > size[son[cur]]) {
son[cur] = nx;
}
}
}
}
void dfs2(int cur, int tp) {
top[cur] = tp;
dfn[cur] = ++dfs_clock;
dfm[dfs_clock] = cur;
if(son[cur]) dfs2(son[cur], tp);
for(int i = 0; i < G[cur].size(); i++) {
int nx = G[cur][i];
if(nx != fa[cur] && nx != son[cur]) {
dfs2(nx, nx);
}
}
low[cur] = dfs_clock;
}
int lca(int x, int y) {
int t1 = top[x], t2 = top[y];
while(t1 != t2) {
if(deep[t1] < deep[t2]) {
swap(x, y); swap(t1, t2);
}
x = fa[t1], t1 = top[x];
}
return deep[x] < deep[y] ? x : y;
}
int getAnc(int x, int depth) {
while(deep[top[x]] > depth) x = fa[top[x]];
return dfm[dfn[top[x]] + depth - deep[top[x]]];
}
struct Node {
pair<int, int> val;
int tag;
Node *ls, *rs;
void pushUp() {
if(ls->val.first == rs->val.first) {
val = make_pair(ls->val.first, ls->val.second + rs->val.second);
} else {
val = min(ls->val, rs->val);
}
}
void update(int t) {
val.first += t;
tag += t;
}
void pushDown() {
if(tag) {
ls->update(tag);
rs->update(tag);
tag = 0;
}
}
}pool[MAXN<<1];
Node *newNode() {
static int cnt = 0;
return &pool[cnt++];
}
Node *build(int l, int r) {
Node *cur = newNode();
if(l < r) {
int mid = (l + r) / 2;
cur->ls = build(l, mid);
cur->rs = build(mid + 1, r);
cur->pushUp();
} else {
cur->val = make_pair(0, 1);
cur->tag = 0;
}
return cur;
}
void add(Node *cur, int l, int r, int a, int b, int v) {
if(a <= l && b >= r) {
cur->update(v);
} else {
cur->pushDown();
int mid = (l + r) / 2;
if(a <= mid) add(cur->ls, l, mid, a, b, v);
if(b > mid) add(cur->rs, mid + 1, r, a, b, v);
cur->pushUp();
}
}
pair<int, int> query(Node *cur, int l, int r, int a, int b) {
if(a <= l && b >= r) {
return cur->val;
} else {
int mid = (l + r) / 2;
cur->pushDown();
pair<int, int> ls = make_pair(INT_MAX, INT_MAX);
pair<int, int> rs = make_pair(INT_MAX, INT_MAX);
if(a <= mid) ls = query(cur->ls, l, mid, a, b);
if(b > mid) rs = query(cur->rs, mid + 1, r, a, b);
if(ls.first == rs.first) {
return make_pair(ls.first, ls.second + rs.second);
} else {
return min(ls, rs);
}
}
}
struct Info {
int y1, y2, v;
};
vector<Info> vec[MAXN];
void add(int x1, int x2, int y1, int y2, int v) {
vec[x1].push_back(Info{y1, y2, v});
vec[x2 + 1].push_back(Info{y1, y2, -v});
}
void add(int x, int y, int v) {
int z = lca(x, y);
if(z != x && z != y) {
add(dfn[x], low[x], dfn[y], low[y], v);
add(dfn[y], low[y], dfn[x], low[x], v);
} else {
if(y == z) swap(x, y);
// x is the lca(x, y);
x = getAnc(y, deep[x] + 1);
if(dfn[x] > 1) {
add(dfn[y], low[y], 1, dfn[x] - 1, v);
add(1, dfn[x] - 1, dfn[y], low[y], v);
}
if(low[x] < n) {
add(dfn[y], low[y], low[x] + 1, n, v);
add(low[x] + 1, n, dfn[y], low[y], v);
}
}
}
int main() {
scanf("%d %d", &n, &k);
vector<pair<int, int> > E;
for(int i = 1; i < n; i++) {
int x, y;
scanf("%d %d", &x, &y);
E.push_back(make_pair(x, y));
G[x].push_back(y);
G[y].push_back(x);
}
dfs1(1, 0, 1); dfs2(1, 1);
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= min(n, i + k); j++) {
add(i, j, 1);
}
}
long long ans = 0;
Node *root = build(1, n);
for(int i = 1; i <= n; i++) {
for(int j = 0; j < vec[i].size(); j++) {
Info cur = vec[i][j];
add(root, 1, n, cur.y1, cur.y2, cur.v);
}
pair<int, int> cur = root->val;
if(cur.first == 0) {
ans += cur.second;
}
}
printf("%lld\n", (ans + n) / 2);
return 0;
}
T3
有一个奇妙的思路
计算每一个b[i]与对应a[i]的位置差绝对值之和tot
然后找到最大的i使得2*(i - 1)是tot的约数且i不大于n
然鹅爆零
出题者本意是要练大家打表找规律。。。
注:要学会用程序打表哦 【吐血
不知道题目给出操作是什么效果时 打表吧
部分分:循环同构 kmp
知识点补充:即在s1后续一个s1 然后拿s2在里面kmp
一堆大讨论。。。
n是奇数:ans = n - 1
n是偶数:
数列是排列且逆序对有偶数个 ans = n - 2
数列是排列且逆序对有奇数个 ans = n - 1
有重复 ans = n - 1
打表及标程如下
//打表
#include <bits/stdc++.h>
using namespace std;
int solve(int n, int k) {
string s;
for(int i = 1; i <= n; i++) {
s += (char)(i + '0');
}
queue<string> Q;
map<string, int> vis;
Q.push(s);
vis[s] = 1;
while(!Q.empty()) {
string cur = Q.front(); Q.pop();
for(int i = 0; i < cur.size(); i++) {
// [i, i + k - 1]
if(i + k - 1 >= cur.size()) break;
string nx = cur;
for(int j = i + k - 1; j > i; j--) {
swap(nx[j], nx[j - 1]);
}
if(!vis[nx]) {
Q.push(nx);
vis[nx] = 1;
}
}
}
return vis.size();
}
int main() {
int n = 9;
for(int k = 2; k <= 9; k++) {
cerr << solve(n, k) << endl;
}
return 0;
}
//标程:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool checkNull(const vector<int> & a, const vector<int> & b) {
vector<int> A(a), B(b);
sort(A.begin(), A.end());
sort(B.begin(), B.end());
return A != B;
}
int circularMin(const vector<int> & a) {
int n = a.size();
vector<int> s(a.size() + a.size());
for(int i = 0; i < s.size(); i++) {
s[i] = a[i % a.size()];
}
int i = 0, j = 1, k;
while(i < n && j < n) {
for(k = 0; s[i + k] == s[j + k]; k++);
if(k >= n) break;
if(s[i + k] > s[j + k]) i += k + 1;
else j += k + 1;
if(i == j) j++;
}
return i < j ? i : j;
}
bool checkN(const vector<int> & a, const vector<int> & b) {
int p1 = circularMin(a);
int p2 = circularMin(b);
for(int i = 0; i < a.size(); i++) {
if(a[p1] != b[p2]) return false;
p1 = (p1 + 1) % a.size();
p2 = (p2 + 1) % a.size();
}
return true;
}
bool checkUnique(const vector<int> & a) {
vector<int> A(a);
for(int i = 1; i < A.size(); i++) {
if(A[i] == A[i - 1]) return false;
}
return true;
}
ll calc(const vector<int> & a) {
int n = a.size();
vector<int> p(a);
sort(p.begin(), p.end());
p.erase(unique(p.begin(), p.end()), p.end());
vector<int> A(n);
for(int i = 0; i < n; i++) {
A[i] = lower_bound(p.begin(), p.end(), a[i]) - p.begin() + 1;
}
vector<int> c(n + 1);
auto sum = [&](int x) {
int ret = 0;
for(; x >= 1; x -= x & -x) ret += c[x];
return ret;
};
auto add = [&](int x, int y) {
for(; x <= n; x += x & -x) c[x] += y;
};
ll res = 0;
for(int i = n - 1; i >= 0; i--) {
res += sum(A[i] - 1);
add(A[i], 1);
}
return res;
}
int main() {
int T;
cin >> T;
while(T--) {
int n;
cin >> n;
vector<int> a(n), b(n);
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < n; i++) cin >> b[i];
if(checkNull(a, b)) {
cout << -1 << endl;
} else if(checkN(a, b)) {
cout << n << endl;
} else {
if(n % 2 == 0 && checkUnique(a)) {
int p1 = calc(a) % 2;
int p2 = calc(b) % 2;
if(p1 == p2) {
cout << n - 1 << endl;
} else {
cout << n - 2 << endl;
}
} else {
cout << n - 1 << endl;
}
}
}
return 0;
}
附赠万能头 #include <bits/stdc++.h>