信息课闲着无聊打的一场cf模拟赛。
A题:
*题目描述:
已知一个等差数列的首项和公差,问某个数在不在等差数列内?
*题解:
直接模拟,注意零和负数要判,不然直接模会出错。
*代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
int main()
{
// setfile();
R int a = FastIn(), b = FastIn(), c = FastIn();
bool ans;
if (!c) ans = a == b;
else
if (c > 0) ans = b >= a && ((b - a) % c == 0);
else ans = b <= a && ((a - b) % (-c) == 0);
printf(ans ? "YES" : "NO");
return 0;
}
B题:
*题目描述:
已知一个3*3矩阵的(1,2)(2,1)(2,3)(3,2)四个点,求剩下的五个空有多少种不同的方案,使得每个2*2方格内的数之和都相等,同时保证填上去的数都在1~n范围内。
*题解:
设左上角的数为x,根据等量关系可以推出剩下三个角上面的表达式,然后就枚举x,判断剩下三个数是不是合法的就可以,中间那个数填什么都可以,所以答案*n就可以了。
*代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
int main()
{
// setfile();
R int n = FastIn(), a = FastIn(), b = FastIn(), c = FastIn(), d = FastIn();
R long long ans = 0;
#define ok(_x) ((_x) >= 1 && (_x) <= n)
for (R int i = 1; i <= n; ++i)
if (ok(i + b - c) && ok(i + a - d) && ok(i + a + b - c - d)) ++ans;
printf(LL"
", ans * n);
return 0;
}
C题:
*题目描述:
有一个长度为n的数组a,每一次可以将某个位置的数移到旁边的位置上(1的旁边是2和n,n的旁边是n-1和1),问最少的移动步数是多少?
*题解:
答案就是n-前缀和出现次数的最多的次数。因为这是一个环,每次出现一个和为0的段,那么此处的答案就是这段的长度-1,所以只要统计有多少个答案为0的段。所以我们把所有的前缀和都取出来,两个相同的前缀和之间一定是和为0的段,所以n-出现次数最多的前缀和就是答案。
*代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#include <map>
std::map<long long, int> cnt;
int main()
{
// setfile();
R int n = FastIn(), ans = 1;
R long long s = 0;
for (R int i = 1; i <= n; ++i)
{
s += FastIn();
++cnt[s];
cmax(ans, cnt[s]);
}
printf("%d
", n - ans );
return 0;
}
D题:
*题目描述:
给定一棵BST的插入的顺序,输出每次插入的节点的父亲。
*题解:
比赛的时候sb地写了一个模拟每次在BST上暴力插,结果交上去光荣地T了,突然想到一条链的话就被卡成n2的了。然后自己画了画图,发现答案就是序列里的upper_bound。我当时对此的解决方法是离散化后用链表把所有的数串起来,然后倒序处理插入操作,这样就变成了在树上的删除操作,可以用链表来维护,这样它的父亲就是链表左右两端的出现时间的较大值。(我也不知道当时是怎么想出这个算法的,也不知道是不是对的,但是不知道为什么交上去运气好居然就ac了)
*代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 100010
int a[maxn], b[maxn], next[maxn], prev[maxn], n, tim[maxn], ans[maxn];
int main()
{
// setfile();
n = FastIn();
for (R int i = 1; i <= n; ++i)
a[i] = b[i] = FastIn();
std::sort(b + 1, b + n + 1);
for (R int i = 1; i <= n; ++i)
a[i] = std::lower_bound(b + 1, b + n + 1, a[i]) - b,
tim[a[i]] = i, next[i] = i + 1, prev[i] = i - 1;
tim[0] = tim[n + 1] = 0;
for (R int i = n; i > 1; --i)
{
next[prev[a[i]]] = next[a[i]];
prev[next[a[i]]] = prev[a[i]];
ans[i] = b[tim[next[a[i]]] > tim[prev[a[i]]] ? next[a[i]] : prev[a[i]]];
}
for (R int i = 2; i <= n; ++i) printf("%d ", ans[i] );
return 0;
}
E题:
*题目描述:
有n个站点,对于站点i(1≤i<n) ,它到达i+1 到 ai的代价都为1,且不能往编号小于它的点走。求最短路的邻接矩阵的总和。
*题解:
第一眼是floyd,发现数据范围跑不过。(于是考场就弃疗了),于是就想DP,对于每个i,枚举自己所能到达的点的ai 最大的点。写出DP方程:dpi=dpj−(ai−j)+n−i−1,其中j为上述的最优的点。然后j可以用线段树/树状数组/ST表来维护,于是复杂度降为O(nlogn)。
*代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif
#define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b), 0 : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b), 0 : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 1 << 20
int a[maxn], M, n;
struct Seg
{
int val, pos;
inline bool operator < (const Seg &that) const {return val < that.val || (val == that.val && pos < that.pos); }
inline bool operator > (const Seg &that) const {return val > that.val || (val == that.val && pos > that.pos); }
}tr[maxn];
inline void Build()
{
for (R int i = 0; i < n; ++i) tr[i + M] = (Seg){a[i], i};
for (R int i = M - 1; i; --i)
tr[i] = dmax(tr[i << 1], tr[i << 1 | 1]);
}
inline int get(R int s, R int t)
{
Seg ans = (Seg) {-1, -1};
for (s = s + M - 1, t = t + M + 1; s ^ t ^ 1; s >>= 1, t >>= 1)
{
if (~ s & 1) cmax(ans, tr[s ^ 1]);
if (t & 1) cmax(ans, tr[t ^ 1]);
}
return ans.pos;
}
long long dp[maxn];
int main()
{
// setfile();
n = FastIn();
for (R int i = 0; i < n - 1; ++i)
a[i] = FastIn() - 1;
a[n - 1] = n - 1;
for (M = 1; M < n; M <<= 1);
Build();
R long long ans = 0;
for (R int i = n - 2; i >= 0; --i)
{
R int m = get(i + 1, a[i]);
dp[i] = dp[m] - (a[i] - m) + n - i - 1;
ans += dp[i];
}
printf(LL"
", ans);
return 0;
}