Codeforces Round #353(Div 2)

信息课闲着无聊打的一场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(1i<n) ,它到达i+1ai的代价都为1,且不能往编号小于它的点走。求最短路的邻接矩阵的总和。
*题解:
第一眼是floyd,发现数据范围跑不过。(于是考场就弃疗了),于是就想DP,对于每个i,枚举自己所能到达的点的ai 最大的点。写出DP方程:dpi=dpj(aij)+ni1,其中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;
}
原文地址:https://www.cnblogs.com/cocottt/p/6765004.html