考完自闭了,怎么能这么菜......


$\text{julian}$

考虑分成公元前,$1582.10.4$ 及以前,$1582.10.15$ 以后三种情况。

暴力模拟即可。

//Code By CXY07
#include<bits/stdc++.h>
using namespace std;

#define FILE
#define int long long
#define debug(x) cout << #x << " = " << x << endl
#define LL long long
#define pii pair<int, int>
#define lowbit(x) ((x) & (-(x)))
#define pb push_back

const int MAXN = 1;
const int INF = 2e9;
//const int mod = 998244353;
//const int mod = 1e9 + 7;

int T, r, to1, to1582, ans;
int day[20] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

template<typename T> inline void read(T &a) {
    a = 0; char c = getchar(); int f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {a = (a * 10) + (c ^ 48); c = getchar();}
    a *= f;
}

void BC(int x) {
    int tot = 1461, y = 4713, m = 1, d = 1;
    y -= x / tot * 4; x %= tot;
    for(int i = y, dd;; --i) {
        dd = (i % 4 == 1 ? 366 : 365);
        if(x >= dd) x -= dd, y = i - 1;
        else break;
    }
    if(y % 4 == 1) day[2]++;
    for(int i = 1; i <= 12; ++i) {
        if(x >= day[i]) m = i + 1, x -= day[i];
        else break;
    }
    if(y % 4 == 1) day[2]--;
    d += x;
    printf("%lld %lld %lld BC\n", d, m, y);
}

void AC1(int x) {
    int y = 1, m = 1, d = 1, tot = 1461;
    y += (x / tot) * 4; x %= tot;
    for(int i = y, dd;; ++i) {
        dd = (i % 4 ? 365 : 366);
        if(x >= dd) x -= dd, y = i + 1;
        else break;
    }
    if(y % 4 == 0) day[2]++;
    for(int i = 1; i <= 12; ++i) {
        if(x >= day[i]) x -= day[i], m = i + 1;
        else break;
    }
    if(y % 4 == 0) day[2]--;
    d += x;
    printf("%lld %lld %lld\n", d, m, y);
}

void AC2(int x) {
    int tot = 146097, y = 1582, m = 10, d = 15;
    y += (x / tot) * 400; x %= tot;
    for(int i = y, dd;; ++i) {
        if((i + 1) % 400 == 0) dd = 366;
        else if((i + 1) % 4 == 0 && (i + 1) % 100 != 0) dd = 366;
        else dd = 365;
        if(x >= dd) x -= dd, y = i + 1;
        else break;
    }
    if(x <= day[10] - 15) {
        d += x;
        printf("%lld %lld %lld\n", d, m, y);
        return;
    }
    x -= day[10] - 14;
    m = 11, d = 1;
    for(int i = 11; i <= 12; ++i) {
        if(x >= day[i]) x -= day[i], m = i + 1;
        else break;
    }
    if(m != 13) {
        d += x;
        printf("%lld %lld %lld\n", d, m, y);
        return;
    }
    y++, m = 1, d = 1;
    if(y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) day[2]++;
    for(int i = 1; i <= 12; ++i) {
        if(x >= day[i]) x -= day[i], m = i + 1;
        else break;
    }
    if(y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) day[2]--;
    d += x;
    printf("%lld %lld %lld\n", d, m, y);
}

signed main () {
    for(int i = 4713; i >= 1; --i) {
        if(i % 4 == 1) to1 += 366;
        else to1 += 365;
    }
    to1582 = to1;
    for(int i = 1; i <= 1581; ++i) {
        if(i % 4 == 0) to1582 += 366;
        else to1582 += 365;
    }
    for(int i = 1; i <= 9; ++i) to1582 += day[i];
    to1582 += 4;//1582.10.5(15)
    read(T);
    while(T--) {
        read(r);
        if(r < to1) BC(r);
        else if(r < to1582) AC1(r - to1);
        else AC2(r - to1582);
    }
    return 0;
}

出题人很有精神!


$\text{zoo}$

随便分位考虑一下,求有哪些饲料存在,然后暴力每一位判断。如果该位可以放,就 $\times 2$ 。注意 $n=0,k=64$ 的时候 $2^{64}$ 会炸 $\text{unsigned long long}$,谢谢出题人送我退役。

//Code By CXY07
#include<bits/stdc++.h>
using namespace std;

#define FILE
//#define int unsigned long long
#define ull unsigned long long
#define debug(x) cout << #x << " = " << x << endl
#define LL long long
#define pii pair<int, int>
#define lowbit(x) ((x) & (-(x)))
#define pb push_back

const int MAXN = 1.1e6 + 10;
const int INF = 2e9;
//const int mod = 998244353;
//const int mod = 1e9 + 7;

int n, m, c, k, cnt2 = 0;
ull a[MAXN], ans = 0, p2[70];
int p[MAXN], q[MAXN], lsh[MAXN], Lim;
bool ok[70], use[MAXN];

template<typename T> inline void read(T &a) {
    a = 0; char c = getchar(); int f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {a = (a * 10) + (c ^ 48); c = getchar();}
    a *= f;
}

inline int Getid(int x) {
    return lower_bound(lsh + 1, lsh + Lim + 1, x) - lsh;
}

signed main () {
    read(n); read(m); read(c); read(k);
    p2[0] = 1;
    for(int i = 1; i < k; ++i)
        p2[i] = p2[i - 1] << 1ull;
    for(int i = 1; i <= n; ++i) read(a[i]); 
    for(int i = 1; i <= m; ++i) {
        read(p[i]); read(q[i]);
        lsh[i] = q[i];
    }
    sort(lsh + 1, lsh + m + 1);
    Lim = unique(lsh + 1, lsh + m + 1) - lsh - 1;
    for(int i = 1; i <= m; ++i) q[i] = Getid(q[i]);
    for(int s = 0; s < k; ++s) {
        for(int i = 1; i <= n; ++i) {
            if(a[i] & p2[s]) {
                ok[s] = true;
                break;
            }
        }
    }
    for(int i = 1; i <= m; ++i) 
        if(ok[p[i]]) use[q[i]] = true;
    memset(ok, true, sizeof ok);
    for(int i = 1; i <= m; ++i)
        if(!use[q[i]]) ok[p[i]] = false;
    for(int i = 0; i < k; ++i) 
        if(ok[i]) cnt2++;
    if(n == 0 && cnt2 == 64) return puts("18446744073709551616"), 0;
    if(cnt2) ans = 1;
    for(int i = 1; i <= cnt2; ++i) ans *= 2;
    cout << ans - n << endl;
    return 0;
}

曾经,不开 $\text{long long}$ 见祖宗;今天,开了 $\text{unsigned long long}$ 我还是见祖宗了。


$\text{call}$

怎么考场上这题都写不出......

根据部分分极强的提示 我们不难发现函数调用关系是一个 $\text{DAG}$。又每一个加法实际上是独立的,只需要乘一下后面的所有乘法操作即可。

考虑建出 $\text{DAG}$,正反各做一遍 $\text{toposort}$(令被调用的函数向调用他的函数的边为正)。

先通过反图求出经过每一个点的乘法操作,然后通过正图更新每一个加法操作即可。

可以把初始的 $a$ 看做 $n$ 个加法标记,或许会稍微简单一些。

//Code By CXY07
#include<bits/stdc++.h>
using namespace std;

//#define FILE
#define int long long
#define debug(x) cout << #x << " = " << x << endl
#define file(FILENAME) freopen(FILENAME".in", "r", stdin), freopen(FILENAME".out", "w", stdout)
#define LINE() cout << "LINE = " << __LINE__ << endl
#define LL long long
#define ull unsigned long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fst first
#define scd second
#define inv(x) qpow((x),mod - 2)
#define lowbit(x) ((x) & (-(x)))
#define vec vector

const int MAXN = 1e6 + 10;
const int INF = 2e9;
const double PI = acos(-1);
const double eps = 1e-6;
//const int mod = 1e9 + 7;
const int mod = 998244353;
//const int G = 3;
//const int base = 131;

struct EDGE {
    int head[MAXN], edgesize;
    int nxt[MAXN << 1], to[MAXN << 1];
    inline void addedge(int x, int y) {
        nxt[++edgesize] = head[x];
        to[edgesize] = y;
        head[x] = edgesize;
    }
} e;

int n, m, q;
int a[MAXN], t[MAXN], p[MAXN], v[MAXN];
int c[MAXN], cnt[MAXN], s[MAXN], dp[MAXN];
int ind[MAXN], top[MAXN], ccnt;
vec<int> g[MAXN], w[MAXN];
queue<int> Q;

template<typename T> inline bool read(T &a) {
    a = 0; char c = getchar(); int f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {a = a * 10 + (c ^ 48); c = getchar();}
    a *= f;
    return 1;
}

template<typename A, typename ...B>
inline bool read(A &x, B &...y) {return read(x) && read(y...);}

signed main () {
    read(n);
    for(int i = 1; i <= n; ++i)
        read(a[i]);
    read(m);
    for(int i = 1; i <= m; ++i) {
        read(t[i]);
        if(t[i] == 1) read(p[i]), read(v[i]);
        if(t[i] == 2) read(v[i]);
        if(t[i] == 3) {
            read(c[i]);
            for(int j = 1, x; j <= c[i]; ++j) {
                read(x), g[i].pb(x);
                e.addedge(i, x);
                ind[x]++;
            }
        }
    }
    read(q);
    for(int i = 1; i <= q; ++i) {
        read(s[i]);
        e.addedge(0, s[i]);
        ind[s[i]]++;
    }
    for(int i = 0; i <= m; ++i) if(!ind[i]) Q.push(i);
    while(Q.size()) {
        int x = Q.front(); Q.pop();
        top[++ccnt] = x;
        for(int i = e.head[x], to; i; i = e.nxt[i]) {
            to = e.to[i];
            if(!(--ind[to])) Q.push(to);
        }
    }
    for(int ii = ccnt, x; ii >= 1; --ii) {
        x = top[ii];
        if(t[x] == 2) cnt[x] = v[x];
        else cnt[x] = 1;
        for(int i = e.head[x], to; i; i = e.nxt[i]) {
            to = e.to[i];
            w[x].pb(cnt[x]);
            (cnt[x] *= cnt[to]) %= mod;
        }
    }
    dp[0] = 1;
    for(int ii = 1, x; ii <= ccnt; ++ii) {
        x = top[ii];
        for(int i = e.head[x], pos = 0, to; i; i = e.nxt[i], ++pos) {
            to = e.to[i];
            (dp[to] += dp[x] * w[x][pos] % mod) %= mod;
        }
    }
    for(int i = 1; i <= n; ++i)
        (a[i] *= cnt[0]) %= mod;
    for(int i = 1; i <= m; ++i)
        if(t[i] == 1) (a[p[i]] += v[i] * dp[i] % mod) %= mod;
    for(int i = 1; i <= n; ++i)
        printf("%lld ", a[i]);
    return 0;
}

$\text{snakes}$

考虑如果一条蛇选择结束,需要满足什么条件。

如果他吃掉最后一名之后,没有变成最后一名,那么他一定选择吃。称这样是必吃状态。

由于整个序列是递增的,如果他吃了最后一名而没有掉到最后一名,会使得序列的 $\min$ 增大,$\max$ 减小。那么新的第一名如果选择吃,那一定会落到原先第一名更后面。

那就让新的第一名去选择是否结束,反正我吃了不会比他先死。

如果他吃掉最后一名之后,变成了最后一名,那么找到距离他最近的必吃状态,我吃不吃只和与这个必吃状态的 距离 的 奇偶性 相关。

设我在 $p$,最近的必吃状态位置是 $s$。

首先显然的是 $s$ 处必定会吃,那考虑 $s$ 到 $p$ 之间的蛇,他们一定不是必吃状态,那一定有:这些蛇选择吃之后的新状态的体力值单调。

也就是说,如果 $s$ 吃,他一定吃的是 $s+1$。$s+1$ 知道自己会被吃,那么他就选择不吃最小的;$s+1$ 不吃,就会选择结束,那么 $s+2$ 就知道自己就算变成最后,也不会死,那么他一定选择吃......

也就是,如果 $p-s$ 是奇数,他就会结束游戏,否则一定会吃掉最小的,而接下来新的第一名就一定会直接结束游戏。

然后拿队列模拟一下,和 $\text{NOIP2016}$ 蚯蚓一样维护一个双端队列,每次从原队列和新队列取 $\max$ 和 $\min$ 更新即可。

只要遇上一个非必吃状态,就 $\mathcal{O(n)}$ 模拟找到下一个必吃状态,返回答案即可。

//Code By CXY07
#include<bits/stdc++.h>
using namespace std;

//#define FILE
//#define int long long
#define debug(x) cout << #x << " = " << x << endl
#define file(FILENAME) freopen(FILENAME".in", "r", stdin), freopen(FILENAME".out", "w", stdout)
#define LINE() cout << "LINE = " << __LINE__ << endl
#define LL long long
#define ull unsigned long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fst first
#define scd second
#define inv(x) qpow((x),mod - 2)
#define lowbit(x) ((x) & (-(x)))
#define vec vector

const int MAXN = 1e6 + 10;
const int INF = 2e9;
const double PI = acos(-1);
const double eps = 1e-6;
//const int mod = 1e9 + 7;
//const int mod = 998244353;
//const int G = 3;
//const int base = 131;

struct NODE {
    int x, y;
    NODE(int _x = 0, int _y = 0) : x(_x), y(_y) {}
    bool operator < (const NODE &b) const {
        return (x < b.x) || (x == b.x && y < b.y);
    }
    bool operator > (const NODE &b) const {
        return b < (*this);
    }
    NODE operator - (const NODE &b) const {
        return NODE(x - b.x, y);
    }
    bool operator == (const NODE &b) const {
        return x == b.x && y == b.y;
    }
    bool operator != (const NODE &b) const {
        return !((*this) == b);
    }
} q[3][MAXN << 1];

int T, n, m;
int l[3], r[3];
int a[MAXN];

template<typename T> inline bool read(T &a) {
    a = 0; char c = getchar(); int f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {a = a * 10 + (c ^ 48); c = getchar();}
    a *= f;
    return 1;
}

template<typename A, typename ...B>
inline bool read(A &x, B &...y) {return read(x) && read(y...);}

NODE GetMax(bool del) {
    NODE res = NODE(-INF, -INF);
    int pos = 0;
    if(l[1] <= r[1] && q[1][r[1]] > res) res = q[1][r[1]], pos = 1;
    if(l[2] <= r[2] && q[2][r[2]] > res) res = q[2][r[2]], pos = 2;
    if(!del) return res;
    assert(pos);
    r[pos]--;
    return res;
}

NODE GetMin(bool del) {
    NODE res = NODE(INF, INF);
    int pos = 0;
    if(l[1] <= r[1] && q[1][l[1]] < res) res = q[1][l[1]], pos = 1;
    if(l[2] <= r[2] && q[2][l[2]] < res) res = q[2][l[2]], pos = 2;
    if(!del) return res;
    assert(pos);
    l[pos]++;
    return res;
}

int GetPos(int siz) {
    int cnt = 1;
    for(int i = siz + 1; i <= n; ++i) {
        if(i == n - 1) return n - 1;
        NODE mx = GetMax(1), mn = GetMin(1);
        NODE New = mx - mn;
        q[2][--l[2]] = New;
        if(GetMin(0) != New) return i;
    }
    return n;
}

int solve() {
    l[1] = n, r[1] = n - 1;
    l[2] = n, r[2] = n - 1;
    for(int i = 1; i <= n; ++i) 
        q[1][++r[1]] = NODE(a[i], i);
    int siz = n, now = 0;
    for(int i = 1; i <= n; ++i) {
        if(i == n - 1) return 1;
        NODE mx = GetMax(1), mn = GetMin(1);
        NODE New = mx - mn;
        q[2][--l[2]] = New;
        if(GetMin(0) == New) {
            int pos = GetPos(i);
            if((pos - i) & 1) return n - (i - 1);
            else return n - (i - 1) - 1;
        }
    }
    return 1;
}

signed main () {
    read(T);
    for(int tt = 1, k; tt <= T; ++tt) {
        if(tt == 1) {
            read(n);
            for(int i = 1; i <= n; ++i)
                read(a[i]);
        } else {
            read(k);
            for(int i = 1, x, y; i <= k; ++i) {
                read(x); read(y);
                a[x] = y;
            }
        }
        printf("%d\n", solve());
    }
    return 0;
}

标签: 位运算, dp, 模拟, 博弈论, 拓扑排序

添加新评论