CSP2020-S2 题解

T1 儒略日

分为两种情况。

  1. 在1582年10月4日以前

    每4年有一个闰年,我们先确定在答案前4年内的某一年(的1月1日),然后一年一年增加,再一月一月增加,再一日一日增加。

    我们可以把公元前x年当作公园-x+1年。

  2. 在1582年10月15日以后

    每400年有97个闰年,就确定答案前400年的某一年(的1月1日),跟上面一样这么干就OK了。

代码

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define fp( i, b, e ) for ( int i(b), I(e); i <= I; ++i )
#define fd( i, b, e ) for ( int i(b), I(e); i >= I; --i )
#define i64 long long

int Q; i64 n;
int a[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check( int y ){
    return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

int main(){
//    open("julian");
    scanf( "%d", &Q );
    while( Q-- ){
        scanf( "%lld", &n );
        if ( n <= 2299160 ){ // 1582 10 4
            int y = -4712 + n / (365 * 4 + 1) * 4, m = 1, d = 1; n %= (365 * 4 + 1);
            while( n >= 365 + (y % 4 == 0) ) n -= 365 + (y % 4 == 0), ++y;
            while( n >= a[m] + (m == 2 && y % 4 == 0) ) n -= a[m] + (m == 2 && y % 4 == 0), ++m;
            d += n;
            if ( y <= 0 ) printf( "%d %d %d BC\n", d, m, -y + 1 );
            else printf( "%d %d %d\n", d, m, y );
        } else { // 1582 10 15
            n = n - 2299160 + 286;
            int y = 1582, m = 1, d = 1;
            y += n / (365 * 400 + 97) * 400, n %= (365 * 400 + 97);
            while( n >= 365 + check(y) ) n -= 365 + check(y), ++y;
            while( n >= a[m] + (m == 2 && check(y)) ) n -= a[m] + (m == 2 && check(y)), ++m;
            d += n;
            printf( "%d %d %d\n", d, m, y );
        }
    }
    return 0;
}

T2 动物园

我们先把所有动物的编号或起来,如果第x位为1,那对于所有 的i,将 塞进集合S;对于 的i,第 位不能为1。

连 unsigned long long 都不够。

所以随手写个高精度就可以了。(呵呵

代码

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define fp( i, b, e ) for ( int i(b), I(e); i <= I; ++i )
#define fd( i, b, e ) for ( int i(b), I(e); i >= I; --i )
#define i64 long long
#define u64 unsigned long long

const int _ = 1e6 + 55;
int N, M, C, K; u64 S1; bool S2;
bitset<100000055> vs; bool flg[100];
int p[_], q[_];
char str[100]; int n, ans[100];

bool check( int x ){ return ((S1 >> x) & 1) || (x == 64 && S2); }

int main(){
//    open("zoo");
    scanf( "%d%d%d%d", &N, &M, &C, &K ); u64 x; bool y; char t;
    fp( i, 1, N ){
        x = 0, y = 0, scanf( "%s", str );
        if ( strlen(str) > 20 && strcmp(str, "18446744073709551616") >= 0 ) y = 1;
        fp( i, 0, strlen(str) - 1 ) x = x * 10 + (str[i] & 15);
        S1 |= x, S2 |= y;
    }
    fp( i, 1, M ){
        scanf( "%d%d", p + i, q + i );
        if ( check(p[i]) ) vs[q[i]] = 1;
    }
    fp( i, 1, M ) if ( !check(p[i]) && !vs[q[i]] && !flg[p[i]] ) flg[p[i]] = 1, --K;
    ans[n = 1] = 1;
    fp( i, 1, K ){
        fp( j, 1, n ) ans[j] <<= 1;
        fp( j, 1, n ) if ( ans[j] >= 10 ) ans[j + 1] += ans[j] / 10, ans[j] %= 10;
        if ( ans[n + 1] ) ++n;
    }
    ans[1] -= N;
    fp( i, 1, n ) if ( ans[i] < 0 ){ int t((-1 - ans[i]) / 10 + 1); ans[i + 1] -= t, ans[i] += t * 10; } else break;
    while( n > 1 && !ans[n] ) --n;
    fd( i, n, 1 ) printf("%d", ans[i]);
    printf("\n");
    return 0;
}

T3 函数调用

再增加一个3类函数 ,调用

最终只要调用一次函数 再输出答案。

我们将函数视为节点,将 类函数 向调用的函数 连有向边。

因为函数不会直接或间接地调用本身,所以建成的有向图是

DFS 一遍 ,如果将所有访问到 类函数按顺序排成一个序列 ,按顺序执行后序列就是答案啦。

原序列 对最终答案的影响为

类函数 对最终答案的影响为

表示节点调用函数 所有直接/非直接调用的 类函数 的乘积。

然后再按拓扑序扫一遍,记录一下之后所有系数之和,将贡献全部计算进去就可以了。

代码

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define fp( i, b, e ) for ( int i(b), I(e); i <= I; ++i )
#define fd( i, b, e ) for ( int i(b), I(e); i >= I; --i )
#define i64 long long

const int _ = 1e5 + 55, mod = 998244353;
int N, M, a[_], s1[_], s2[_];
int T[_], P[_], V[_];
vector<int> g[_], e[_];
queue<int> Q; int ind[_], top[_], n;

int main(){
//    open("call");
    scanf( "%d", &N );
    fp( i, 1, N ) scanf( "%d", a + i );
    scanf( "%d", &M ); int x;
    fp( i, 1, M ){
        scanf( "%d", T + i );
        if ( T[i] == 1 ) scanf( "%d%d", P + i, V + i );
        else if ( T[i] == 2 ) scanf( "%d", V + i );
        else if ( T[i] == 3 ){
            scanf( "%d", V + i );
            fp( j, 1, V[i] ){
                scanf( "%d", &x ), g[i].push_back(x);
            }
        }
    }
    fp( i, 1, M ) if ( T[i] == 3 ){
        fp( j, 0, (int)g[i].size() - 1 ) if ( T[g[i][j]] == 3 ) e[i].push_back(g[i][j]), ++ind[g[i][j]];
    }
    T[0] = 3; scanf( "%d", V );
    fp( j, 1, V[0] ){
        scanf( "%d", &x ), g[0].push_back(x);
        if ( T[x] == 3 ) e[0].push_back(x), ++ind[x];
    }
    fp( i, 0, M ) if ( T[i] == 3 && !ind[i] ) Q.push(i);
    while( Q.size() ){
        int u = top[++n] = Q.front(); Q.pop();
        for ( int i = 0; i < (int)e[u].size(); ++i )
            if ( !--ind[e[u][i]] ) Q.push(e[u][i]);
    }
    fd( i, n, 1 ){
        int u = top[i], v; s1[u] = 1;
        fp( j, 0, (int)g[u].size() - 1 ){
            v = g[u][j];
            if ( T[v] == 3 ) s1[u] = (i64)s1[u] * s1[v] % mod;
            else if ( T[v] == 2 ) s1[u] = (i64)s1[u] * V[v] % mod;
        }
    }
    fp( i, 1, N ) a[i] = (i64)a[i] * s1[0] % mod;
    s2[0] = 1;
    fp( i, 1, n ){
        int u = top[i], v, t = s2[u];
        fd( j, (int)g[u].size() - 1, 0 ){
            v = g[u][j];
            if ( T[v] == 1 ) a[P[v]] = (a[P[v]] + (i64)t * V[v]) % mod;
            else if ( T[v] == 2 ) t = (i64)t * V[v] % mod;
            else if ( T[v] == 3 ) s2[v] = (s2[v] + t) % mod, t = (i64)t * s1[v] % mod;
        }
    }
    fp( i, 1, N ) printf( "%d%c", a[i], "\n "[i < N] );
    return 0;
}

T4 贪吃蛇

假如最终进行 轮, 表示第 轮时最强的蛇, 表示第 轮最弱的蛇。

那么决斗结束时被吃蛇的序列肯定为 的前缀。

所以只要我们求出 就能 求出答案。

我们用 维护最强🐍和最弱🐍,复杂度为 。加上 可怕的大常数,你可以轻松地

记得 NOIP2016 蚯蚓 么?这题也可以用相似的方法。

题目中 不下降,倒过来扔进 ,将每轮的 扔进

很明显 是越来越弱的,如果 为最弱的, 轮直接拿来当最弱的🐍;否则
强,那么 要比 弱。

这样,就可以 得到答案了。

图1

图2

图3

代码

#include<bits/stdc++.h>
using namespace std;
#define open(s) freopen( s".in", "r", stdin ), freopen( s".out", "w", stdout )
#define fp( i, b, e ) for ( int i(b), I(e); i <= I; ++i )
#define fd( i, b, e ) for ( int i(b), I(e); i >= I; --i )
#define i64 long long

const int _ = 1e6 + 55;

struct node{
    int i, x; node( int a = 0, int b = 0 ):i(a), x(b){}
    bool operator < ( const node &t )const{ return x == t.x ? i < t.i : x < t.x; }
};

int T, N, M, a[_], b[_], c[_], l[_];
node Q1[_], Q2[_]; int hd1, tl1, hd2, tl2;

int work(){
    hd1 = hd2 = 1, tl1 = tl2 = 0;
    fd( i, N, 1 ) Q1[++tl1] = node(i, a[i]);
    fp( i, 1, N - 1 ){
        node mx, mn;
        if ( hd1 <= tl1 && (hd2 > tl2 || Q2[hd2] < Q1[hd1]) ) mx = Q1[hd1++];
        else mx = Q2[hd2++];
        if ( hd1 <= tl1 && (hd2 > tl2 || Q1[tl1] < Q2[tl2]) ) mn = Q1[tl1--];
        else mn = Q2[tl2--];
        b[i] = mn.i, c[i] = mx.i;
        Q2[++tl2] = node(mx.i, mx.x - mn.x);
    }
    int ed = N - 1;
    fp( i, 1, N ) l[i] = 1e9;
    fd( i, N - 1, 1 ){
        if ( l[c[i]] <= ed ) ed = i - 1;
        l[b[i]] = i;
    }
    return N - ed;
}

int main(){
    // open("snakes");
    scanf( "%d%d", &T, &N ); int x, y;
    fp( i, 1, N ) scanf( "%d", a + i );
    printf( "%d\n", work() );
    while( --T ){
        scanf( "%d", &M );
        fp( i, 1, M ) scanf( "%d%d", &x, &y ), a[x] = y;
        printf( "%d\n", work() );
    }
    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务