比赛-CioCio的训练赛 (Aug 18, 2018)

1.) wjj 的子集序列

暴力二进制枚举子集打表,然后可以发现答案就是最大值。根据公式推一波也行吧……

#include <cstdio>
#include <stack>
#include <ctype.h>

using namespace std;

typedef long long ll;

template<typename T>
void rd(T &num)
{
    char tt;
    bool flag = 0;
    while (!isdigit(tt = getchar()) && tt != '-');
    if (tt == '-') num = 0, flag = 1;
    else num = tt - '0';
    while (isdigit(tt = getchar()))
        num = num * 10 + tt - '0';
    if (flag) num = -num;
    return;
}

template<typename T>
void pt(T num)
{
    if (num < 0) putchar('-'), num = -num;
    stack<char> SSS;
    do SSS.push(num % 10 + '0');
    while (num /= 10);
    while (!SSS.empty())
        putchar(SSS.top()), SSS.pop();;
    putchar('\n');
    return;
}

ll ans;

int main()
{
    freopen("subset.in", "r", stdin);
    freopen("subset.out", "w", stdout);

    int N;
    rd(N);
    for (int i = 1; i <= N; ++i) {
        ll t;
        rd(t);
        if (i == 1 || ans < t) ans = t;
    }
    pt(ans);
    return 0;
}

2.) wjj 的排列序列

没有限制条件时,显然最优排列是一个单调下降的排列。比如 $ {5, 4, 3, 2, 1} $ 。只有一个限制条件时,比如要求 \(5\) 在 \(2\) 之后,最优排列是 $ {4, 3, 2, 5, 1} $ 。分析一下可以发现应该尽量把较大的数放在前面,当然是在保证满足限制条件的情况下。简单反证一下,如果不尽量把较大的放在前面,有的数字就会被前面较小的数“压制”,前缀最小值就会变小,所以不行。为了满足限制条件,可以写一个类似 Top-sort 的东西。

#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <stack>
#include <ctype.h>

using namespace std;

template<typename T>
void rd(T &num)
{
    char tt;
    bool flag = 0;
    while (!isdigit(tt = getchar()) && tt != '-');
    if (tt == '-') num = 0, flag = 1;
    else num = tt - '0';
    while (isdigit(tt = getchar()))
        num = num * 10 + tt - '0';
    if (flag) num = -num;
    return;
}

template<typename T>
void pt(T num)
{
    if (num < 0) putchar('-'), num = -num;
    stack<char> SSS;
    do SSS.push(num % 10 + '0');
    while (num /= 10);
    while (!SSS.empty())
        putchar(SSS.top()), SSS.pop();
    putchar('\n');
    return;
}

typedef long long ll;

const int _N = 120000;
const int INF = 1e9;

priority_queue<int> Q;
vector<int> G[_N];
int cnt[_N];

int main()
{
    int N, M;
    rd(N), rd(M);
    for (int a, b, i = 1; i <= M; ++i) {
        rd(a), rd(b);
        G[a].push_back(b);
        ++cnt[b];
    }
    for (int i = 1; i <= N; ++i)
        if (!cnt[i]) Q.push(i);
    int mn = INF;
    ll ans = 0;
    while (!Q.empty()) {
        int t = Q.top();
        Q.pop();
        mn = min(mn, t);
        ans += mn;
        for (int i = G[t].size() - 1; i >= 0; --i)
            if (!--cnt[G[t][i]]) Q.push(G[t][i]);
    }
    pt(ans);
    return 0;
}

3.) wjj 的零一序列

这道题类似 wxh 学长讲过的一道 Codeforces 的题 Queries 。CF 的那道题更加复杂,需要把每个数按二进制拆位,然后用位数那么多棵线段树维护区间信息。这个拆位思想其他题也遇到过,非常有用!另外 wxh 大佬真强啊……当时讲了十多道题,现在已经在其他地方遇到过两道几乎一致的题啦。可能因为 CF 的题,大家都觉得改改就能重新再出一道题吧……
这题先对原序列求前缀异或序列,对后者维护一下区间 0 和 1 的数量,记为 $ v_0, v_1 $ ,然后询问 0 的答案是 $ v_0 \cdot (v_0 - 1) / 2 + v_1 \cdot (v_1 - 1) / 2 $ ,询问 1 的答案是 $ v_0 \cdot v_1 $ 。注意询问原序列 $ [x, y] $ 区间时对应询问的前缀异或序列区间是 $ [x - 1, y] $ 。最后改悔一下,线段树动态开点要注意随时新建儿子节点,考试的时候用到还没建立的儿子节点的信息,更新了当前节点,然后就爆 0 了 OrzOrz 。

#include <cstdio>
#include <algorithm>
#include <stack>
#include <ctype.h>

using namespace std;

#define SC(a, b) (static_cast<a>(b))

template<typename T>
void rd(T &num)
{
    char tt;
    bool flag = 0;
    while (!isdigit(tt = getchar()) && tt != '-');
    if (tt == '-') num = 0, flag = 1;
    else num = tt - '0';
    while (isdigit(tt = getchar()))
        num = num * 10 + tt - '0';
    if (flag) num = -num;
    return;
}

template<typename T>
void pt(T num)
{
    if (num < 0) putchar('-'), num = -num;
    stack<char> SSS;
    do SSS.push(num % 10 + '0');
    while (num /= 10);
    while (!SSS.empty())
        putchar(SSS.top()), SSS.pop();
    putchar('\n');
    return;
}

typedef long long ll;

const int _N = 5000000;

struct data {
    int v0, v1;
    data(int v0 = 0, int v1 = 0):
        v0(v0), v1(v1) { }
};

int Lazy[_N], L[_N], R[_N], V0[_N], V1[_N];
int Rt, Cnt, N, TTT;

void putdown(int &p, int l, int r)
{
    int mid = (l + r) >> 1;

    swap(V0[L[p]], V1[L[p]]), swap(V0[R[p]], V1[R[p]]);
    Lazy[p] ^= 1, Lazy[L[p]] ^= 1, Lazy[R[p]] ^= 1;
    return;
}

void modify(int &p, int l, int r, int s, int t)
{
    if (!p) p = ++Cnt, V0[p] = r - l + 1;
    if (s <= l && r <= t) {
        swap(V0[p], V1[p]);
        Lazy[p] ^= 1;
        return;
    }
    int mid = (l + r) >> 1;
    if (!L[p]) L[p] = ++Cnt, V0[L[p]] = mid - l + 1;
    if (!R[p]) R[p] = ++Cnt, V0[R[p]] = r - mid;
    if (Lazy[p])
        putdown(p, l, r);
    if (t >= l && s <= mid)
        modify(L[p], l, mid, s, t);
    if (t > mid && s <= r)
        modify(R[p], mid + 1, r, s, t);
    V0[p] = V0[L[p]] + V0[R[p]];
    V1[p] = V1[L[p]] + V1[R[p]];
    return;
}

data query(int &p, int l, int r, int s, int t)
{
    if (!p) p = ++Cnt, V0[p] = r - l + 1;
    if (s <= l && r <= t) {
        return data(V0[p], V1[p]);
    }
    int mid = (l + r) >> 1, s0 = 0, s1 = 0;
    if (!L[p]) L[p] = ++Cnt, V0[L[p]] = mid - l + 1;
    if (!R[p]) R[p] = ++Cnt, V0[R[p]] = r - mid;
    if (Lazy[p])
        putdown(p, l, r);
    if (t >= l && s <= mid) {
        data tmp = query(L[p], l, mid, s, t);
        s0 += tmp.v0, s1 += tmp.v1;
    }
    if (t > mid && s <= r) {
        data tmp = query(R[p], mid + 1, r, s, t);
        s0 += tmp.v0, s1 += tmp.v1;
    }
    return data(s0, s1);
}

int main()
{
    rd(N);
    for (int t, i = 1; i <= N; ++i) {
        rd(t);
        if (t) modify(Rt, 0, N, i, N);
    }
    rd(TTT);
    while (TTT--) {
        int ins, x, y;
        rd(ins), rd(x);
        if (ins == 2) {
            modify(Rt, 0, N, x, N);
        } else {
            rd(y);
            data t = query(Rt, 0, N, x - 1, y);
            if (ins == 0) {
                ll s = 0;
                if (t.v0 >= 2) s += SC(ll, t.v0) * (t.v0 - 1) / 2;
                if (t.v1 >= 2) s += SC(ll, t.v1) * (t.v1 - 1) / 2;
                pt(s);
            } else {
                pt(SC(ll, t.v0) * t.v1);
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ghcred/p/9497157.html

时间: 2024-07-30 14:00:35

比赛-CioCio的训练赛 (Aug 18, 2018)的相关文章

比赛-模拟赛 (Aug 18, 2018)

1.) 小X的质数 线性筛就可以了.由唯一分解定理,如果 $ x = p_a \cdot p_b $ ,那么 \(x\) 也一定只能这样分解质因数.所以 \(x\) 也是符合题目条件的数. #include <cstdio> #include <ctype.h> #include <stack> using namespace std; template<typename T> void rd(T &num) { char tt; while (!i

比赛-thh学长的训练赛 (Aug 16, 2018)

1.) 欧拉回路 打表找规律,打了斯特林,打了组合数,找不出,弃疗.我太蠢了,这题和前面这些东西没什么关系啊.考虑 \(n\) 个点时的完全图 \(n \cdot (n - 1) / 2\) 条边,每条边选与不选两种决策,所以可以得到神奇的数字 \(2^{n(n-1)/2}\) ,而答案就是 \(2^{(n-1)(n-2)/2}\) .具体证的话,对于 \(n\) 个点的图,拿出一个点,把 \(n-1\) 个点胡乱连边,方案数 \(2^{(n-1)(n-2)/2}\) .然后让单独拿出来的点与其

最后一周第二天训练赛之第二题

试题: B - B Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice SPOJ ICODER Description Mathews uses a brand new 16-bit instruction processor. (Yeah i am being sarcastic!). It has one register (say R) and it su

Dream_Chaser队训练赛第一场 I题

Dream_Chaser队训练赛第一场 I题 题目来自2012成都区域赛 I - Count Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4472 Description Prof. Tigris is the head of an archaeological team who is currently in charge of a

2017后期 第 1 场训练赛

题目依次为 NKOJ 上 P3496 P4236 P3774 P2407 1.数三角形 方法很多, 比如推出三边 x y z 的限制关系, 然后加加减减得到计算式子 不过也可以用观察法, 暴力计算出 n 为 1 至 13 对应的结果为: 0 0 0 1 3 7 13 22 34 50 70 95 125 相邻两数差为: 0 0 1 2 4 6 9 12 16 20 25 30 这些相邻两数相邻差又为: 0 1 1 2 2 3 3 4 4 5 5 找到规律了, 如果结果第 i 项为第 i - 1

CSU-ACM2014暑假集训基础组训练赛(1) 解题报告

•Problem A HDU 4450                 水题,签到题 水题..没啥好说的.给大家签到用的. 1 #include <cstdio> 2 int main(){ 3 int n,a,ans; 4 while(scanf("%d",&n),n){ 5 ans = 0; 6 for(int i = 0;i < n;i++){ 7 scanf("%d",&a); 8 ans += a*a; 9 } 10 pr

cumt训练赛题解

2017年4月3日 cumt2017春季--训练赛(1) A.HihoCoder 1339 (dp) 思路: 比较清晰呢,就是个dp吧.定义一下状态,dp[i][j]:前i个骰子,扔出点数和为j的方案数.然后不就很好写了嘛递推式,dp[i][j] = dp[i - 1][j - k](1<=k<=6). 好像题就做完了诶,可是窝wa了两发什么鬼.第一发爆int,第二发爆longlong,这里的trick就是方案数可能非常大,所以这题的应该把状态定义为dp[i][j]:前i个骰子,扔出点数和为j

CSU-ACM暑假集训基础组训练赛(4)解题报告

•Problem A SPOJ SUB_PROB   AC自动机 •题意: 给定一个长为M(M≤100000 )的文本串,和N(N≤1000)个长度不超过2000的模式串,问每个模式串是否在文本串中出现过? •几乎和周一课件上的第一个例题一模一样.. •把文本串丢到AC自动机里面去跑. •注意: •1.可能有两个相同的模式串(略坑吧.) •2.一个模式串可能是另一个模式串的后缀,即如果一个点的fail指针指向的点是一个“危险节点”,那么它本身也是一个“危险节点”. 1 #include <ios

HDU 4864 Task (贪心+STL多集(二分)+邻接表存储)(杭电多校训练赛第一场1004)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4864 解题报告:有n台机器用来完成m个任务,每个任务有一个难度值和一个需要完成的时间,每台机器有一个可以工作的最长时间和一个可以完成的任务的难度的最大值, 一台机器能完成一个任务的条件是这台机器的最长工作时间和能完成任务的难度值必须都大于等于这个任务,而且一台机器最多完成一个任务,假设一个任务的时间为t,难度值为x,那么完成这个任务可以赚到的钱 money = 500 * t + 2 * x; 现在