Codeforces Contest #1325 解题报告 & 题目大意

A EhAb AnD gCd

题目大意

给定一个整数 $x(2\leq x \leq 10^9)$

求 $a,b$ 满足 $\gcd(a,b) + \operatorname{lcm}(a,b) = x$

多组解输出任意一个

Code

这有啥说的,随便找个质因数让后输出 $p, x$ 就可以

// Woshiluo Luo<[email protected]>
// 2020/03/14 22:36:48

#include <cmath>
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

int t, x;

int main() {
    scanf( "%d", &t );
    while( t -- ) {
        scanf( "%d", &x );
        int sq = std::sqrt(x) + 1;
        for( int i = 1; i <= sq; i ++ ) {
            if( x % i == 0 ) {
                int tmp = ( x / i ) - 1;
                if( tmp == 0 )
                    continue;
                printf( "%d %d\n", i, tmp * i );
                break;
            }
        }
    }
}

B CopyCopyCopyCopyCopy

题目大意

给你一个长度为 $n$ 的数列 $a$, 现在你可以复制无数个 $a$ 接到原来的数列后面

问这样接完后,最长严格上升子序列的长度

Code

因为可以接无限次,所以直接输出数字个数就可以了

// Woshiluo Luo<[email protected]>
// 2020/03/14 22:42:47
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 1e5 + 1e4;

int t;
int n;
int a[N];

int main() {
    scanf( "%d", &t );
    while( t -- ) {
        scanf( "%d", &n );
        for( int i = 1; i <= n; i ++ ) {
            scanf( "%d", &a[i] );
        }
        std::sort( a + 1, a + n + 1 );
        int cnt = 0, la = 0;
        for( int i = 1; i <= n; i ++ ) {
            if( i == 1 || a[i] != la ) {
                la = a[i];
                cnt ++;
            }
        }
        printf( "%d\n", cnt );
    }
}

C Ehab and Path-etic MEXs

题目大意

给一棵节点数为 $n$ 的树

现在你要给每条边一个边权,要求:

  • 边权为一个整数 $v(0\leq v \leq n – 2)$
  • 每条边的边权不能和别的边的相同

现在定义 $MEX(u,v)$ 为 $u,v$ 之间的最短简单路径上没有出现的边权中的最小值

请给出一种边权方案,最小化 $\max{MEX(u,v)}$

思路

考虑每条边会被算进去多少次,记为每条边的贡献

贡献越大给越大的边就可以了

实际上可以更加简化,因为无论如何一定有一个 $MEX \geq 2$

所以我们尽可能避免 $0,1,2$ 出现在一条边上即可

随便找一个度数 $\geq 2$ 的点,把这三个数字放上去即可

如果没有这种点,那么怎么摆都会有一条 $MEX=n-1$ 的路径

Code

// Woshiluo Luo<[email protected]>  
// 2020/03/14 22:52:18
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 1e5 + 1e4;

// Edge Start
struct edge {
    int to, next, val;
} e[ N << 1 ];
int ehead[N], ecnt;
inline void add_edge( int now, int to, int val ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    e[ecnt].val = val;
    ehead[now] = ecnt;
}
// Edge End

struct node { long long val; int id; } max[N];
bool cmp( node _a, node _b ) { return _a.val < _b.val; }

int n, x, y;
int son[N], val[N];

void dfs( int now, int la ) {
    son[now] = 1;
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == la )
            continue;
        dfs( e[i].to, now );
        son[now] += son[ e[i].to ];
        max[ e[i].val ].val = ( 1LL * son[ e[i].to ] * ( n - son[ e[i].to ] ) );
    }
}

int main() {
#ifdef woshiluo
    freopen( "c.in", "r", stdin );
    freopen( "c.out", "w", stdout );
#endif
    scanf( "%d", &n );
    for( int i = 1, u, v; i < n; i ++ ) {
        max[i].id = i;
        scanf( "%d%d", &u, &v );
        add_edge( u, v, i );
        add_edge( v, u, i );
    }

    dfs( 1, 0 );

    std::sort( max + 1, max + n, cmp );

    for( int i = 1; i < n; i ++ ) {
        val[ max[i].id ] = i - 1;
    }

    for( int i = 1; i < n; i ++ ) {
        printf( "%d\n", val[i] );
    }
}

D Ehab the Xorcist

给定两个整数 $u,v$ 求最短的数列 $a$ 满足

  • $$ \sum a = v $$
  • xor 和为 $u$

多解输出任意一个

无解输出 $-1$

题目大意

这题感觉的 C 简单啊

满足 $xor$ 容易,满足 $v$ 的话需要难度

考虑最后 $xor$ 的结果受每个二进制位的和的奇偶性影响

因此可以确定每一位的奇偶性

然后随便搞一下满足 $v$ 就可以了

Code

// Woshiluo Luo<[email protected]>
// 2020/03/14 23:39:20
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

unsigned long long u, v;
int bit_u[110], bit_less[110], bit_cnt[110];
std::vector<unsigned long long> ans;

inline void noans() {
    printf( "-1\n" );
    exit(0);
}

void to_bit( unsigned long long a, int bit[] ) {
    int cnt = 0;
    while( a ) {
        bit[ ++ cnt ] = a & 1;
        a >>= 1;
    }
}

int main() {
    scanf( "%llu%llu", &u, &v );
    if( v < u )
        noans();

    to_bit( v - u, bit_less );
    to_bit( u, bit_u );

    for( int i = 1; i <= 100; i ++ ) {
        bit_cnt[i] = bit_u[i];
    }
    int p = 64;
    int cnt = 0;
    while( p ) {
        bit_cnt[p] += ( cnt - ( cnt & 1 ) );
        cnt = cnt & 1;
        if( bit_less[p] )
            cnt ++;
        p --; cnt <<= 1;
    }

    if( cnt != 0 )
        noans();

    bool flag = true;
    while( flag ) {
        flag = false;
        unsigned long long out = 0;
        unsigned long long p = 1;
        for( int i = 1; i <= 64; i ++, p <<= 1 ) {
            if( bit_cnt[i] ) {
                out = out | p;
                bit_cnt[i] --;
                flag = true;
            }
        }
        if( flag )
            ans.push_back(out);
    }

    cnt = ans.size();
    printf( "%d\n", cnt );
    for( int i = 0; i < cnt; i ++ ) {
        printf( "%llu ", ans[i] );
    }

}

E Ehab’s REAL Number Theory Problem

题目大意

给你一个长度为 $n$ 的数列,保证数列中每个数字有不超过 $7$ 个因数

请求出最短的子序列,使子序列成绩为完全平方数

思路

这题比 F 题难吧…

首先由 保证数列中每个数字有不超过 $7$ 个因数 得每个数不会有超过两个 $1$ 和其本身以外的质因数

然后我们可以先把每个数里的完全平方数因子先除掉,因为这些不会对答案造成影响

这样下来每个数的因子只有 1 和其本身以及两个质因数(前提是这个数不是质数)

然后建图,如果这个数是质数,将其和 $1$ 连接,如过不是将其的两个质因数连接

剩下就是求最小环

Code

// Woshiluo Luo<[email protected]>
// 2020/03/15 22:08:53

#include <cmath>
#include <cstdio>
#include <cstring>

#include <queue>
#include <vector>
#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 1e6 + 1e4;
const int M = 1100;
const int INF = 0x3f3f3f3f;

int n, ans = INF;
int dis[N], fa[N];
bool marked[N], pool[N];

// Edge Start
struct edge {
    int cur, to, next;
} e[ N << 1 ];
int ehead[N], ecnt = 1;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].cur = now;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

int bfs( int st ) {
    memset( dis, INF, sizeof(dis) );
    memset( fa, 0, sizeof(fa) );
    std::queue<int> q;
    q.push(st); dis[st] = 0;
    while( !q.empty() ) {
        int cur = q.front(); q.pop();
        for( int i = ehead[cur]; i; i = e[i].next ) {
            if( e[i].to == fa[cur] )
                continue;

            if( dis[ e[i].to ] >= INF ) {
                fa[ e[i].to ] = cur;
                dis[ e[i].to ] = dis[cur] + 1;
                q.push( e[i].to );
            }
            else {
                return dis[cur] + dis[ e[i].to ] + 1;
            }
        }
    }
    return INF;
}

int main() {
    scanf( "%d", &n );
    for( int i = 1, x; i <= n; i ++ ) {
        scanf( "%d", &x );
        std::vector<int> a;
        int cnt = std::sqrt(x) + 1;
        while(cnt > 1) {
            int cnt_pow = cnt * cnt;
            while( x % cnt_pow == 0 )
                x /= cnt_pow;
            cnt --;
        }
        if( x == 1 )
            chk_Min( ans, 1 );
        if( pool[x] )
            chk_Min( ans, 2 );
        pool[x] = true;
        int tmp = std::sqrt(x);
        for( int j = 2; j <= tmp; j ++ ) {
            if( x % j == 0 ) {
                a.push_back(j);
                a.push_back( x / j );
                break;
            }
        }
        if( a.size() == 0 ) {
            add_edge( 1, x );
            add_edge( x, 1 );
        }
        else if( a.size() != 0 ) {
            add_edge( a[0], a[1] );
            add_edge( a[1], a[0] );
        }
    }

    if( ans != INF ) {
        printf( "%d\n", ans );
        return 0;
    }

    for( int i = 1; i <= 1000; i ++ ) {
        if( ehead[i] )
            chk_Min( ans, bfs(i) );
    }

    if( ans >= INF )
        ans = -1;

    printf( "%d\n", ans );
}

F Ehab’s Last Theorem

题目大意

给定一个 $n$ 个节点的图

令 $glo=\lceil\sqrt{n}\rceil$

你要么找到一个长度和 $glo$ 相等的环

要么找到一个比 $glo$ 小的独立集

Code

先试图找环,找不到肯定有独立集

// Woshiluo Luo<[email protected]>  
// 2020/03/15 15:49:32
#include <cstdio>
#include <cstring>

#include <stack>
#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 1e5 + 1e4;
const int M = 2e5 + 1e4;

int n, m, need;

int dep[N];
bool vis[N];
std::stack<int> st;

// Edge Start
struct edge { int to, next; } e[ M << 1 ];
int ehead[N], ecnt;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End


void dfs( int now ) {
    st.push(now);
    dep[now] = st.size();
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( dep[ e[i].to ] == 0 )
            dfs( e[i].to );
        else if( dep[now] - dep[ e[i].to ] + 1 >= need ) {
            int size = dep[now] - dep[ e[i].to ] + 1;
            printf( "%d\n%d\n", 2, size );
            for( int i = 1; i <= size; i ++ ) {
                printf( "%d ", st.top() );
                st.pop();
            }
            exit(0);
        }
    }
    if( !vis[now] ) {
        for( int i = ehead[now]; i; i = e[i].next ) {
            vis[ e[i].to ] = true;
        }
    }
    st.pop();
}

int main() {
#ifdef woshiluo
    freopen( "f.in", "r", stdin );
    freopen( "f.out", "w", stdout );
#endif
    scanf( "%d%d", &n, &m );
    while( need * need < n )
        need ++;

    while( m -- ) {
        int u, v;
        scanf( "%d%d", &u, &v );
        add_edge( u, v ); add_edge( v, u );
    }

    dfs(1);

    printf( "%d\n", 1 );
    int cnt = 0;
    for( int i = 1; i <= n; i ++ ) {
        if( vis[i] == false ) {
            printf( "%d ", i );
            cnt ++;
        }
        if( cnt == need )
            break;
    }
}

Codeforces Contest #1312 解题报告 & 部分翻译

比赛链接:Educational Codeforces Round 83 (Rated for Div. 2)

A Two Regular Polygons

1 题目大意

给你两个正多边形,一个 $n$ 条边 $A$ ,一个 $m$ 条边 $B$

问 $B$ 有没有可能被 $A$ 包含且所有顶点都与 $A$ 的某一个节点重合

有输出 YES ,否则输出 NO

2 Code

判 $n \bmod m = 0$ 就可以了

#include <cstdio>

int T;
int n, m;

int main() {
    scanf( "%d", &T );
    while( T -- ) {
        scanf( "%d%d", &n, &m );
        printf( "%s\n", ( n % m == 0 )? "YES": "NO" );
    }
}

B Bogosort

1 题目大意

给你一个长度为 $n$ 的序列 $a$, 你可以将 $a$ 重新排序,使其满足 $j – a_j \neq i – a_i$

输出任何一个即可

保证有解

$n \leq 100$

2 思路

$$
\begin{aligned}
j – a_j & \neq i – a_i \\
j – i & \neq a_j – a_i
\end{aligned}
$$

直接从大到小输出

3 Code

// Woshiluo Luo<[email protected]>  
// 2020/03/09 22:40:32 
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 110;

int T;
int n;
int a[N];

int main() {
    scanf( "%d", &T );
    while( T -- ) {
        scanf( "%d", &n );
        for( int i = 1; i <= n; i ++ ) {
            scanf( "%d", &a[i] );
        }
        std::sort( a + 1, a + n + 1 );
        for( int i = n; i >= 1; i -- ) {
            printf( "%d ", a[i] );
        }
        printf( "\n" );
    }
}

C Adding Powers

1 题目大意

给你两个长度为 $n$ 的数列 $a,v$

其中 $a$ 通过输入提供,$v$ 初始所有值为 $0$

接下来,对于第 $i$ 次操作(从 $0$ 计数),你可以

  • 选择任意一个 $v_i$ 增加 $k^i$
  • 什么都不做

问你是否通过多次操作后,使 $v$ 变成 $a$

能输出 YES ,否则输出 NO

2 思路

首先对于每个数字 $a$, 考虑其是否可以变成多个 $k^i$ 的和(不能有重复的 $i$)

能的话算出来,看看有没有和之前重复的,有就不可能

不能的话直接没有可能

3 Code

// Woshiluo Luo<[email protected]>
// 2020/03/09 22:58:45
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 110;

int T;
int n;
long long k;
bool vis[N];
long long a[N];

inline void wrong() {
    printf( "NO\n" );
}

inline void right() {
    printf( "YES\n" );
}

void calc() {
    for( int i = 1; i <= n; i ++ ) {
        if( a[i] == 0 ) {
            continue;
        }
        long long cur = a[i];
        int cnt = 1;
        while( cur ) {
            int tmp = cur % k;
            if( tmp > 1 ) {
                wrong();
                return ;
            }
            if( tmp == 1 ) {
                if( vis[cnt] == false )
                    vis[cnt] = true;
                else {
                    wrong();
                    return ;
                }
            }
            cur /= k;
            cnt ++;
        }
    }
    right();
}

int main() {
    scanf( "%d", &T );
    while( T -- ) {
        memset( vis, 0, sizeof(vis) );

        scanf( "%d%lld", &n, &k );
        for( int i = 1; i <= n; i ++ ) {
            scanf( "%lld", &a[i] );
        }

        calc();
    }
}

D Count the Arrays

1 题目大意

你需要寻找这样的数列个数

  • 有 $n$ 个元素
  • 每个数字都是 $1$ 到 $m$ 之间的整数
  • 只有恰好一对数字相等
  • 数列先严格递增,再严格递减

个数对 $998244353$ 取模后输出

$2 \leq n \leq m \leq 2 \times 10^5$

2 思路

式子题,看 Code 去

3 Code

// Woshiluo Luo<[email protected]>
// 2020/03/09 23:21:18
#include <cstdio>
#include <cstring>

#include <algorithm>

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

const int N = 2e5 + 1e4;
const int mod = 998244353;

inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline void add_eq( int &a, int b ) { a = ( a + b ) % mod; }
inline void mul_eq( int &a, int b ) { a = ( 1LL * a * b ) % mod; }

int ksm( int a, int p ) {
    int res = 1;
    while(p) {
        if( p & 1 )
            res = mul( res, a );
        a = mul( a, a );
        p >>= 1;
    }
    return res;
}

inline int get_inv( int a ) { return ksm( a, mod - 2 ); }

int n, m, sum, ans;
int fact[N], inv[N];

void init() {
    fact[1] = 1;
    for( int i = 2; i <= m; i ++ ) {
        fact[i] = mul( fact[ i - 1 ], i );
    }
    inv[m] = get_inv( fact[m] );
    for( int i = m - 1; i >= 1; i -- ) {
        inv[i] = mul( inv[ i + 1 ], i + 1 );
    }
    inv[0] = 1;
    fact[0] = 1;
}

// Get C^a_b
inline int C( int a, int b ) {
    if( a <= 0 )
        return 1;
    if( b <= 0 )
        return 1;
    return mul( mul( fact[b], inv[ b - a ] ), inv[a] );
}

int main() {
#ifdef woshiluo
    freopen( "d.in", "r", stdin );
    freopen( "d.out", "w", stdout );
#endif
    scanf( "%d%d", &n, &m );
    init();

    for( int i = n - 1; i <= m; i ++ ) {
        add_eq( sum, mul( C( n - 3, i - 2 ), mul( m - i + 1, n - 2 ) ) );
    }

    for( int i = 2; i < n; i ++ ) {
        add_eq( ans, mul( sum, C( i - 2, n - 3 ) ) );
    }

    printf( "%d\n", ans );
}

E Array Shrinking

1 题目大意

这好像是个原题

给你一个长度为 $n$ 的数列 $a$

如果 $a_i = a_{i + 1}$, 那么这两个数可以合并成 $a_i + 1$

问最小数列长度

$1 \leq a_i \leq 1000, 1 \leq n \leq 500$

2 思路

区间 dp

设 $f_{i,j}$ 为 $i$ 到 $j$ 最小长度

$merged_{i,j}$ 为 $i$ 到 $j$ 合并出来的数字

然后就是标准板子了

3 Code

// Woshiluo Luo<[email protected]>
// 2020/03/10 15:50:48
#include <cstdio>
#include <cstring>

#include <algorithm>

const int N = 510;

template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }

int n;
int a[N];
int f[N][N], merged[N][N];

int main() {
#ifdef woshiluo
    freopen( "e.in", "r", stdin );
    freopen( "e.out", "w", stdout );
#endif
    scanf( "%d", &n );
    for( int i = 1; i <= n; i ++ ) {
        scanf( "%d", &a[i] );
        f[i][i] = 1;
        merged[i][i] = a[i];
    }
    for( int len = 2; len <= n; len ++ ) {
        for( int left = 1, rig = len; rig <= n; left ++, rig ++ ) {
            f[left][rig] = rig - left + 1;
            for( int mid = left; mid < rig; mid ++ ) {
                int &f_left = f[left][mid], &f_rig = f[ mid + 1 ][rig],
                &merge_left = merged[left][mid], &merge_rig = merged[ mid + 1 ][rig];
                chk_Min( f[left][rig], f_left + f_rig );
                if( f_left == 1 && f_rig == 1 && merge_left == merge_rig ) {
                    f[left][rig] = 1;
                    merged[left][rig] = merge_left + 1;
                }
            }
        }
    }
    printf( "%d\n", f[1][n] );
}

AGC 034 F RNG and XOR

题目连接: https://atcoder.jp/contests/agc034/tasks/agc034_f

道理我都懂,可是不看题解不到啊……

$$\newcommand \xor{\mathbin{\mathbf{xor}}}$$

1 题意

给定一个数字 $n$

对于 $0 \cdots 2^n – 1$ 中每个数字都有一个 $a_i$

现在有一个数 $X$, 一开始为 $0$

每一次操作会随机选择一个数字 $i$ (其中 $0 \leq i \leq 2^n – 1$,选中 $i$ 的概率为 $\frac{a_i}{\sum a}$)

然后令 $X = X \oplus i$

问使 $X=i$ 的期望次数

2 思路

先令
$$p_i=\frac{a_i}{\sum a}$$

令 $f_i$ 表示从 $i$ 到 $0$ 的期望次数,这和从 $0$ 到 $i$ 显然是一样的

接着有一个非常显然的式子

$$
\begin{aligned}
f_i &= f_{i \xor j} \times p_j + 1 ( i \neq 0 )\\
f_i – 1 &= f_{i \xor j } \times p_j ( i \neq 0 )
\end{aligned}
$$

然后我们就可以得到这个式子

$$ (f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \\
= ( x, f_1 – 1, f_2 – 1, \cdots, f_{2^{n-1}} – 1, f_{2^n-1} – 1 ) $$

但是 $x$ 是未知的

注意到 $\sum p = 1$ 所以左边右边的和是相等的

所以

$$
\begin{aligned}
x &= \sum_{i=0}^{2^n-1} f_i – \sum_{i=1}^{2^n-1} f_i – 1 \\
&= f_0 + 2^n – 1
\end{aligned}
$$

$$
(f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \\
= ( f_0 + 2^n – 1, f_1 – 1, f_2 – 1, \cdots, f_{2^{n-1}} – 1, f_{2^n-1} -1 )
$$

我们需要的使其中两个式子没有未知数

注意到如果使 $p_0 = p_0 – 1$

那么右边每一个数都会减去 $f_i$

$$
(f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0 – 1, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \\ = ( 2^n – 1, – 1, – 1, \cdots, -1, -1 )
$$

于是就可以放进 FWT 里直接做

然后你就发现这东西跑出来是错的……

为什么呢

$$
\begin{aligned}
\mathbf{P} & = (p_0 – 1, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \\
\mathbf{A} & = ( 2^n – 1, – 1, – 1, \cdots, -1, -1 )
\end{aligned}
$$

因为 $\mathbf{P}$ 和 $\mathbf{A}$ FWT 后第一位都是 $0$

没有办法倒推出来 $f_0$

但是可以发现 $f$ 的值是可以平移的

$$ f_i + k = \sum_{i=0}^{2^n-1} p_j(f_{i \oplus j} + k) + 1 = \sum_{i=0}^{2^n-1} f_{i \oplus j} \times p_j + k + 1 $$

那么我们又知道 $f_i = 0$

所以将 $f$ 每一位都减去 $f_0$ 即可

3 Code

#include <cstdio> 

const int N = 1 << 20;
const int mod = 998244353;

int n;
int a[N], b[N], p[N], sum;

inline i
nt add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline void add_eq( int &a, int b ) { a = ( a + b ) % mod; }
inline void mul_eq( int &a, int b ) { a = ( 1LL * a * b ) % mod; }

int ksm( int a, int p ) {
    int res = 1;
    while( p ) {
        if( p & 1 )
            res = mul( res, a );
        a = mul( a, a );
        p >>= 1;
    }
    return res;
}
inline int inv( int a ) { return ksm( a, mod - 2 ); }

void XOR( int *f, int len, int x = 1 ) {
    for( int o = 2, k = 1; o <= len; o <<= 1, k <<= 1 ) {
        for( int i = 0; i < len; i += o ) {
            for( int j = 0; j < k; j ++ ) {
                add_eq( f[ i + j ], f[ i + j + k ] );
                f[ i + j + k ] = add( f[ i + j ], add( - f[ i + j + k ], - f[ i + j + k ] ) );
                mul_eq( f[ i + j ], x ); mul_eq( f[ i + j + k ], x );
            }
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( "F.in", "r", stdin );
    freopen( "F.out", "w", stdout );
#endif
    scanf( "%d", &n );
    n = 1 << n;
    for( int i = 0; i < n; i ++ ) {
        scanf( "%d", &a[i] );
        sum += a[i];
        b[i] = mod - 1;
    }
    sum = inv(sum);
    for( int i = 0; i < n; i ++ ) {
        p[i] = mul( a[i], sum );
    }

    b[0] = n - 1; p[0] -= 1;
    XOR( b, n ); XOR( p, n );
    for( int i = 0; i < n; i ++ ){
        mul_eq( b[i], inv( p[i] ) );
    }
    XOR( b, n, inv(2) );
    for( int i = 0; i < n; i ++ ) {
        printf( "%d\n", ( ( add( b[i], -b[0] ) + mod ) % mod ) );
    }
}

将 Bilibili 缓存转换成视频

0 环境 & 提示

  • 电脑
    • PHP
    • Bash
  • 手机
    • Bilibili 国内版 5.54.0

这样子转换出来还是有水印的,请不要在未经 UP 主同意的情况下传播或用在非法行为

1 过程

因为要备份手机,就想着能不能把 Bilbili 的缓存转换成普通视频留在电脑上

然后看了一下下载目录,里面有一个 video.m4saudio.m4s

mpv 一打开,发现刚好一个是视频一个是音频…

剩下的事情就是拿 ffmpeg 合并一下的事情…

随便胡个脚本就行了

2 脚本

covert.sh
# Author: Woshiluo<[email protected]>
#!/bin/bash

work_dir=`pwd`;
fa_php=`pwd`"/fa.php";
part_php=`pwd`"/part.php";

echo $part_php;
mkdir -p "$work_dir/output"

function covert() {
	cp "$fa_php" ./
	cp "$part_php" ./
	fa=`php fa.php`
	part=`php part.php`
	echo "[INFO] Coverting $fa $part..."
	rm fa.php part.php
	mkdir -p "$work_dir/output/$fa"
	for file in `ls`; do
		if [ -d $file ]; then 
			cd $file
			ffmpeg -i video.m4s -i audio.m4s -c copy "$work_dir/output/$fa/$part.mkv" -y >/dev/null 2>&1
			cd ..
		fi
	done
	echo "[INFO] Done!"
}

for file in `ls`; do
	if [ -d $file ] && [ $file != "output" ]; then
		cd ./$file
		for video in `ls`; do
			if [ -d $video ]; then
				cd ./$video
				covert
				cd ..
			fi
		done
		cd ..
	fi
done
fa.php
<?php

$_file = file_get_contents( "./entry.json" );

$desc = json_decode( $_file );

echo $desc -> title;
part.php
<?php

$_file = file_get_contents( "./entry.json" );

$desc = json_decode( $_file );

echo $desc -> page_data -> part;

随便胡的脚本

把这三个文件放到 Bilibili 的下载目录下,然后执行 covert.sh 就行了

执行过后转换过的文件会在 output 目录下

Atcoder ARC 103 F Distance Sums

0 写在之前

这几天写的题目并不算少

然而这道题是唯一一个看过去傻了的题目…

应该以前听过,题面看着眼熟

可是死活不会做…

1 思路

基本上可以明确是到构造题

这里依赖两个性质:

树的中心的 $D$ 值是最小的

$$ D(fa) = D(x) – n + 2 \times size[i] $$

这个就是标准的树和树的重心的性质

可以推出来如果以重心做根,那么 $D$ 越大越在下面

所以尝试生成一颗以重心为根的树就行了

然后我发现我不会判否

结果发现最后生成出来树判断一次就行了…

2 实现

读入 $D$ 排序

从大到小依此根据上面的式子找父亲

最后判断一下是否正确就可以了

3 Code

// User: woshiluo
// Email: [email protected]
// Problem link: https://atcoder.jp/contests/arc103/tasks/arc103_d
// Comment: 
// Why the problem id is 'F', but the link is 'arc103_d'
// Interesting

#include <cstdio>
#include <cstdlib>

#include <map>
#include <algorithm>

const int N = 1e5 + 1e3;

int n;
int size[N], father[N];

struct node{
	int id;
	long long d;
} a[N];

std::map<long long, int> mp;

void wrong() {
	printf( "-1\n" );
	exit(0);
}
bool cmp( node _a, node _b ) { return _a.d < _b.d; }

int main() {
#ifdef woshiluo
	freopen( "F.in", "r", stdin );
	freopen( "F.out", "w", stdout );
#endif
	scanf( "%d", &n );
	for( int i = 1; i <= n; i ++ ) {
		scanf( "%lld", &a[i].d );
		a[i].id = i;
		size[i] = 1;
		mp[ a[i].d ] = i;
	}
	std::sort( a + 1, a + n + 1, cmp );
	int rt_d, rt;
	rt = a[1].id; rt_d = a[1].d;
	for( int i = n; i > 1; i -- ) {
		int fa = mp[ a[i].d + 2LL * size[ a[i].id ] - n ];
		if( fa == 0 ) {
			wrong();
			return 0;
		} 
		size[fa] += size[ a[i].id ];
		father[ a[i].id ] = fa;
	}
	for( int i = 1; i <= n; i ++ ) {
		if( i == rt ) 
			continue;
		 rt_d -= size[i];
	}
	if( rt_d != 0 ) 
		wrong();

	for( int i = 1; i <= n; i ++ ) {
		if( i == rt ) 
			continue;
		printf( "%d %d\n", father[i], i );
	}
}

HDU 4507 恨7不成妻

思路

裸的要死的数位 DP 题目

一眼看过去,平方和,有点懵

但是维护平方和也是老套路了

维护 $sum$, $cnt$, $pow_sum$ 就可以了

代码

代码写的着急,会有一些不太好看

#include <cstdio>

const int mod = 1e9 + 7;

inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline int power( int a ) { return mul( a, a ); }

int T, max_len;
long long left, rig;
int _count[110][2][10][10][10], _sum[110][2][10][10][10], _pow[110][2][10][10][10];
int max_count[110][2][10][10][10], max_sum[110][2][10][10][10], max_pow[110][2][10][10][10];
bool _vis[110][2][10][10][10];
int a[110];

inline int length( int cur, int len ) {
	int res = cur;
	while( len > 0 ) {
		res = mul( 10, res );
		len --;
	}
	return res;
}

struct node {
	int len, cur, seven, rem, base_rem;
	bool max;
	int& count() {
		if( max ) 
			return max_count[len][seven][rem][cur][base_rem];
		return _count[len][seven][rem][cur][base_rem];
	}
	int& sum() {
		if( max )
			return max_sum[len][seven][rem][cur][base_rem];
		return _sum[len][seven][rem][cur][base_rem];
	}
	int& pow() {
		if( max ) 
			return max_pow[len][seven][rem][cur][base_rem];
		return _pow[len][seven][rem][cur][base_rem];
	}
	bool& vis() {
		return _vis[len][seven][rem][cur][base_rem];
	}
	void print() {
//		printf( "%d %d %d %d %d %d\n", len, cur, seven, rem, base_rem, max );
//		printf( "%d %d %d\n", count(), sum(), pow() );
	}
};

int dfs( node cur ) {
	if( ( ! cur.max ) && cur.vis() )
		return cur.pow();
	if( cur.len == 0 ) {
		if( cur.seven || cur.rem == 0 || cur.base_rem == 0 ) {
			cur.count() = cur.sum() = cur.pow() = 0;
			return cur.pow();
		}
		cur.count() = 1; cur.sum() = cur.cur; cur.pow() = power( cur.cur );
		return cur.pow();
	}
	int &cur_count = cur.count();
	int &cur_sum = cur.sum();
	int &cur_pow = cur.pow();
	if( cur.max ) 
		cur_count = cur_sum = cur_pow = 0;
	for( int i = 0; i <= ( cur.max? a[cur.len]: 9 ); i ++ ) {
		node nxt = cur;
		nxt.len -= 1; nxt.seven = ( cur.seven || ( i == 7 ) ); nxt.cur = i; nxt.max = ( cur.max && i == a[cur.len] );
		nxt.rem = ( cur.rem * 10 + i ) % 7; nxt.base_rem = ( cur.base_rem + i ) % 7;
		dfs( nxt );
		cur_count = add( cur_count, nxt.count() );
		cur_sum = add( cur_sum, add( mul( length( cur.cur, cur.len ), nxt.count() ), nxt.sum() ) );
		cur_pow = add( cur_pow, add( nxt.pow(), add( mul( nxt.count(), power( length( cur.cur, cur.len ) ) ), 
						mul( mul( 2, length( cur.cur, cur.len ) ), nxt.sum() ) ) ) );
	}
	if( cur.max == false )
		cur.vis() = true;
	cur.print();
	return cur_pow;
}

int sum( long long _a ) {
	if( _a == 0 ) 
		return 0;
	if( _a < 0 )
		return 0;
	max_len = 0;
	while( _a ) { 
		a[ ++ max_len ] = _a % 10;
		_a /= 10;
	}
//	printf( "ans: %d\n", dfs( (node){ max_len, 0, 0, 0, 0, true } ) );
	return dfs( (node){ max_len, 0, 0, 0, 0, true } );
}

int main() {
#ifdef woshiluo
	freopen( "hdu.4507.in", "r", stdin );
	freopen( "hdu.4507.out", "w", stdout );
#endif
	scanf( "%d", &T );
	while( T -- ) {
		scanf( "%lld%lld", &left, &rig );
		if( left == 0 ) 
			printf( "%d\n", ( sum(rig) + mod ) % mod );
		else 
			printf( "%d\n", ( add( sum(rig), - sum( left - 1 ) ) + mod ) % mod );
	}
}

Luogu P3177 [HAOI 2015] 树上染色

题目链接: https://www.luogu.com.cn/problem/P3177

0 说在之前

树形 DP 要么模板题,要么神仙题

这个题就属于不太正常的

1 思路

$f_{i,j}$

其中 $i$ 代表当前节点

$j$ 代表子树中选择 $j$ 个黑点,所能对答案产生的贡献

有了这个思路,后面的东西就是标准的树上背包了

2 Code

#include <cstdio>
#include <cstring>

inline int Min(int a, int b) { return a < b? a : b; }
inline long long Max(long long a, long long b) { return a > b? a : b; }

const int N = 2100;

int n, m;
int size[N];

// Edge Start
struct edge {
    int to, val, next;
} e[N << 1];
int ehead[N], ecnt;

inline void add_edge(int now, int to, int val) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].val = val;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

// DP Start
long long f[N][N];
void dp(int now, int la) {
    size[now] = 1;
    f[now][0] = f[now][1] = 0;
    for(int i = ehead[now]; i; i = e[i].next) {
        if( e[i].to == la )
            continue;
        dp(e[i].to, now);
        size[now] += size[ e[i].to ];
        for(int j = Min(size[now], m); j >= 0; j--) {
            for(int k = 0; k <= Min(size[ e[i].to ], j); k++) {
                if( f[now][ j - k ] == -1 )
                    continue;
                long long val = 1LL * ( 1LL * k * ( m - k ) + 1LL * ( size[ e[i].to ] - k ) * ( n - m - size[ e[i].to ] + k ) ) * e[i].val;
                f[now][j] = Max( f[now][j], f[now][j - k] + f[ e[i].to ][k] + val);
            }
        }
    }
}
// DP End

int main() {
#ifdef woshiluo
    freopen("luogu.3177.in", "r", stdin);
    freopen("luogu.3177.out", "w", stdout);
#endif
    scanf("%d%d", &n, &m);
    for(int i = 1, u, v, w; i < n; i++) {
        scanf("%d%d%d", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }

    memset(f, -1, sizeof(f));
    dp(1, 0);

    printf("%lld", f[1][m]);
    fclose(stdin);
    fclose(stdout);
}

2019 年的小小总结

0 序

马上就要从 9102 年到 202 年了呢(不是)

今年是多彩的一年

一年内数不清的变化,造就现在的我

而我会带着这一年的变化,向着前方行走

「凡为过往,皆为序章。」

1 飞速的变化

一切事物都在以想象不到的速度变化着

政策的快速变化,事件的戏剧化反转,一次又一次的拷问我们

还有什么是可信的

还有什么是稳定的

或许我们看不到事情的真相,但是应当尽我们所能,确保所了解情况的真实

做一个不受自媒体和短视频带节奏的人

2 巧妙的缘分

或许是运气很好,有幸在学习的路上优秀的学长们和老师们

甚至还有在中山集训,雅礼集训各个比赛上见到的同学们

能够遇到大家确实是一个了不起的缘分,要加油啊

缘分还体现在自己对于动漫的热爱

无论实在 1 月的动漫星城,还是 8 月的 Aqours 5th Live 上映会与 Bilibili World 2019 广州站,乃至 12 月在北京 Animate 和搜秀城

虽然自己身处全世界离海最远的城市,但是还是有机会,有缘分能够到达这些地方,见到相同爱好的人

缘,妙不可言

3 向前的脚步

或许多多少少有一点算得上梦想的东西

今年有幸参加了几乎整个赛季一直到 NOI 的所有赛事

( CCF NOI WC,APIO,CTS,NOI,CSP)

甚至有幸去 PKUWC 这种神仙比赛

不过比赛成绩倒是都不怎么样,还是要努力啊

4 看不清却值得期待的未来

自主招生政策的不定

进在眼前的中考

这一切都表明了,未来是看不清的

但是我依然相信缘分,相信自己的脚步

看不清的未来,才是值得期待的

5 尾声

https://blog.woshiluo.com/919.html#

从自己在动漫星城时放光的双眼,到搜秀城时的砍价

从 WC 时的铜牌,到 NOI 时的打铁

从混乱的 SYZOJ 魔改,到逐渐形成自己的规范的小脚本

从慌乱不定的 E 类,到波澜不惊的 NOIP 暂停

我是想要发光的,想要在舞台上,发出属于自己的光芒

正是前方迷茫不定,才有着向前走,发光的意义

「私たち、 輝きたい!」

「我们,想要闪闪发光」

「LoveLive! SunShine!!」

+1 附录 – 游记总表

https://blog.woshiluo.com/1077.html

没有写游记的事件

  • 6 – 7 月 雅礼集训
  • 7 月 NOI
  • 8 月 中山纪念中学集训
  • 8 月 Aqours 5th Live 上映会

其他游记/感想不在此处总结

PKUWC 2020(2019) 游记

0 序

晚上十一点半的机房,Woshiluo 正悠闲地考虑着第二天该做的题目

说着他一瞬想起来自己似乎报名过 PKUWC

「过去几年都没有人通过的,今年夏令营整个新疆都没过,果然还是白忙活吧」

话虽这么说,Woshiluo 还是打开了报名网站

「喵喵喵,过了?」

1 Day -2 出发

在经过严密的安检过后

我终于到达了乌鲁木齐站三层

比较有意思是,我的检票口貌似是 A1

然而 A1 前面的人都已经坐满了

我走到夹层,和绝大多数高铁站一样,这个地方是用来骗钱的

不过也就意味着,这里的人会少一点

稍作调整之后,车站广播也响起来了

随着缓慢的人群,我通过了检票口,到达了火车上

2 Day -1 火车上的短暂时光

乌鲁木齐铁路局所销售物品的昂贵已经是有很久历史的事情了

所以如果上车的时候犯懒没有买足吃的东西的话

可以到大站下去购买以尽可能的减少损失

这趟列车绝大部分地区都是没有信号的地方

所以基于手机的娱乐基本上是没有了

Kindel 和随身携带的纸制书可能是最有效的消磨时间方式

所以我在火车上过了一遍绿书,并读完了「樱花庄的宠物女孩」的本篇及番外

我的上铺和下铺都是年轻人,一个考研,一个去内地学习技术

总而言之,大家也都有自己的前途

3 Day 0 慌忙的首都一天

在早上十点,火车到达了北京西站

我从地铁口出来,联系上了 sbr,我从北京西站到国家图书馆再换乘到海淀黄庄

两个人见面稍微寒暄了一小阵,就到星巴克里谈人生

到了快要报道的时间,我们从海淀黄庄坐到北京大学东门 D 出口,从 D 口出来后约 5min 就可以到达报道的地方

我前面比没有几个人,进去之后签到的一栏旁边还有一个 是否使用 NOI Linux

看到这一栏时,就体会到了 PKU 的良心,更不要提后面还有 PKU 食堂 150 CNY 的饭卡

和 sbr 打车到国贸大厦,惊奇的发下自己把一些东西落在了报到处…

算了不重要

然后在和 sbr 吃完午饭后,我坐地铁从国贸到东大桥

经过 5min 的第六感导航,我顺利的到达了 Animate

这里的 Animate 和广东店装修风格好像啊

不过比广东店大了不少

时间超级紧迫,因为很明显,我需要在报道时间结束前回到报道处,拿回自己的东西

所以我就一目十行,随便扫了点 LoveLive! 和 碧蓝航线 的东西就飞速离开了

不过最意外的收获就是搞到了一本 「LoveLive! School idol diary」还是日文原版的

然后一路 Rush 到北京大学的报道处,偷偷的拿到了自己的东西

接着到了自己的酒店,真的离 PKU 好远啊…

稍微整理了一下在 Animate 的战果后跑去和 杨老师 — 我们的教练 会面

然后发现自己这边里所有地铁站都好远啊…

选了个最近的地铁站 — 上地站,然后惊奇的发现 13 号线几乎全是在地表的,我一开始以为这是轻轨,后来发现这东西叫城铁

从上地站出发,换乘两次到鼓楼,然后杨老师告诉我她到雍和宫了

于是从鼓楼出发,换乘一次到雍和宫

后面和老师吃了顿饭,然后和地铁关闭时间赛跑,换乘两次回到上地站

待我再回到酒店的时候,我人已经完全坏掉了

4 Day 1 稍有秩序的开幕

早上在酒店滴滴了 10min +,终与打到了车…

匆匆忙忙,到达开幕式所在场所

认识了几位大佬

开幕式大约介绍了一下北大,然后就散了

然后发现,没有地方休息的说

在经历了一阵混乱后,最后反正是在中关新园定了一间房

嘛,虽然贵的要死,不过明天也算是有地方休息了

反正今天是没有时间了

和教练一起在食堂吃了顿饭

在吃完 PKU 食堂的饭后,真的让人想上 PKU (不是

食堂饭又便宜又好吃,感谢 PKU 给的饭卡

然后跑到考场,Windows 考生使用 Windows 10,具体配置也不清楚

NOI Linux 考生使用的是 Dell 的笔记本,Intel i7,16G DDR4

多余的也没看,毕竟体验很优秀

T1

  • 离谱玩意儿,Subtask 1 随便搞搞就出来了
  • Subtask 2 推了好长时间…没有出来

T2

  • 全肝 T1 和 T3 了
  • 这道题目 Subtask 很多,认真写的花应该有至少 20pts

T3

  • Subtask 1 不用带脑子
  • Subtask 2 离线查分即可,没来的及写
  • 后面的 Subtask 不是我这种人该碰的

告辞 28pts 跑路

在 T1 莽的太久了, T2 T3 好多暴力没拿

中关新园离 pku 是真的近(

回去没有什么事情,就一直在颓废

5 Day 2 PKU 旅游日

面试

据说面试还有紧张到说不出话的

基本上面试文的问题都挺普通的

面试的时候会有一个预定的时间表

我想着我还没到时间,就去食堂买了个面包当早餐

结果回来发现已经到下一个了

无限尴尬

不过还好,面试老师并没有说什么

和一个天津大佬面基成功w

测试

T1

  • 跟着 Subtask 一步步走,基本上都能过
  • 说白了就是人口普查题
  • 我随便在考场上胡了个 $O(n\log^2(n))$ 的,反正过了

T2

  • 神仙,Subtask 1 跑路

T3

  • 最小割?
  • 有一说一,我上次敲网络流应该还是在中山
  • 弃了

最后 100 + 32 + 0 = 132pts

还算可以,基本上算是我的最大能力了(

晚上

回到酒店后,想起今天是冬至,便外卖了份饺子

然而是真的贵

吃完虽然没有吃饱,不过就这样子吧

然后颓废

6 Day 3

早早的就起来了

和 lk 爷爷面基,一起在楼下的包子铺吃了招行

两个人扯皮了好久

Orz lk 太强了

后来两个人打车去 PKU,中间 LK 在 THU 下了

我到了之后刚好开幕

我们教练家女儿生病了,于是我又双是一个人了

闭幕式

一开始大概就是领导讲话

然后就开始讲题

讲下来感觉自己还是很有希望 200 + 的

不过 Day 1 的时候智商下线了w

题倒是都还好,除了 Day 1 T3 完全没搞懂

剩下的都是能听懂但是不会写的(

然后颁奖

我觉得和我没什么关系,就把衣服拉链来开了,毕竟很热

然后惊奇的发现有个三等奖,结果上去的时候拉链没拉上www

晚上

后面发现闭幕式结束才 15 点

直接冲出去坐地铁到搜秀城w

然后再采购

然后就是回宾馆睡觉

晚上和 sbr 再面基

6 Day +1

上午和 Galaxy 见面

(或许是我这次唯一一个面基的成年人?)

然后带我逛了下 THU,顺便在 THU 吃了顿饭

和他聊了一阵子天,受益匪浅

正准备去机场

然后飞机延误了

7 Day +2

意外之喜

于是再去了趟 Animate,好好逛了一把

发现了好多之前没有发现的东西

大收获的说

8 Day +3

飞机又双延误了

告辞,火车真香

CSP 2019 游记

0 序

今年感觉相比较以往还是难了一些的

不过没有大家说的那么夸张倒是真的

不过自己貌似真的变菜了

0.1 吐槽

笔者考完 CSP 就会初中部回了一天

然后周二病到周五

一直在不发烧和低烧徘徊

但是一直咳嗽

咳得人 头疼 + 胸口疼 + 嗓子疼

新疆地邪啊

1 Day 0

今年七十中并不给试机子(注:也有可能是 CCF/科协 不让)

罢了,也没什么看头,每年 11 月都会在七十中冻一下

中午大家一起吃饭

虽然想学习,最后还是放弃了

晚上翻来覆去睡不着,迷迷糊糊最后还是睡了

2 Day 1

2.0 序 – 清晨

早上一开门,哇,下雪了

无论这个比赛怎么改名下雪还是避免不了的

在寒冷的凌晨,我们又拿起武器,向着熟悉的战场再次走去

2.1 CSP – S2 Day 1

T3 是个啥啊?

一中学长们的校车因为各种各样的原因,8:25 才到

遇见了不少以前的熟人,SpinMry,dyf 大家好久不见了,一起加油吧!

匆匆忙忙赶进考场,熟练的敲下 .vimrc,慌的一批

到了时间,准点发题

一直很想问都 9102 年,新疆为什么还是不用压缩包加密这种可靠性高的多的方法

非要用电子教师软件传输,然后再匆匆忙忙断网

罢了,有人愿意举办就不错了

  • T1
    • 属实不带脑子的题目,上来一看基本上就知道从上往下模拟即可 $O(64)$
      不过确实有一种更为简单的办法,参见 Oi-wiki – 格雷码
      最后看数据范围注意到 unsigned long long,出题人太毒瘤了吧
  • T2
    • 随便一看就是瞎搞累计贡献,道理我都懂,这代码怎么写?
      考场上一顿胡写,树上瞎跳,然后写点优化
      写完一开样例3,114514 太臭了,一跑,爆栈了,手写递归去了
      这么一套下来,感觉要出事 $\text{flag}_1$
  • T3
    • 一看,神仙题,10pts 告辞
      等一下这个 10pts 为什么这么难调,时间到了,完蛋

2.2 午休

考完心态小崩,找 dyf 一起快乐

两个人一起吃了饭,然后开始互相吐槽各自的学校

聊完天,两个人有一起走到七十中,路上还在吐槽某大佬的的迷路属性,结果到了七十中校门口就碰到了某大佬

2.3 CSP – J2

先在二楼和 dyf 与 caq 一起聊天 CSP 本质面基大会无疑

然后快考试了才去了三楼,运气可以抽到了比较暖和的位置

  • T1
    • 哇这么水的题目真的有出的必要吗…
  • T2
    • 一开始没看懂在搞什么,还想着 CSP – J2 都考平衡树了?
      后来一看 $price_i \leq 1000$ ,那没事了,多队列维护开溜
  • T3
    • 一眼背包,倒是不知道怎么搞
      弃了
  • T4
    • 最短路题目,怎么搞随缘

一出考场发现 2 道原题过分了啊

T3 我竟然做过,傻了

3 Day 2

3.1 CSP – S2 Day 2

又见熟人,不过因为 Day1 的心态,所以就没有过多闲聊

遇到郭老师,问他 Day 1 爆栈的问题

满口都是什么

「机子环境不重要的啊」
「全国只有两个省份提供了 NOI Linux,还都是虚拟机,别的都是 Windows 」

我看加个「七十中断电和七十中无关」都可以郭老师三连了

顺带一提,Day2 T2 内存 1GB 我们考试环境总共就 1GB 内存,可把我给整乐了

算了,XJ 这个占全国 $\frac{1}{6}$ 领土的小省份还是不要想别的了吧

  • T1
    • 什么玩意儿,神仙,跳
  • T2
    • $O(n^3)$ 是很显然了,就 $f_{i,j}$ 为以 $i$ 结束,向前 $j$ 位的最优答案就行了
      然后对 $i$ 考虑优化,考虑 $i$ 相等的情况下有两种状态 $j,k$,若 $j < k$ 且 $f_{i,j} < f_{i,k}$ 那么 $k$ 状态显然可以舍去
      不就是个弱化版斜率优化吗
  • T3
    • $O(n^2)$ 的点不用带脑子,敲就完事了
      链的点是不带脑子,可是我又双没时间了

3.2 下午

随便在一中食堂买了桶泡面

然后就会机房和大家一起聊天

高二的学长们很大一部分都要退役了,说不好真的是最后一次见了…

祝各位安好

After

一点 CSP 过后的小记

Day +2

选手程序出了

找了几个数据在 NOI Linux 上测试了一下

顺带一提,是远程测试,是真的延迟高…

最后基本上都是

$100 + 55 + 0 + 0 + 64 + 40 = 259$

也不知道官方数据怎么样…

Day +5

斗胆看了下 Day1 T2

发现自己把

st[ st_cnt ] 

写成了

st_cnt

离谱

Day +14

正在去市一中的路上,突然看到有个群里说成绩出了

CCF 又写 Bug了(当然不排除故意的可能性)

一路狂奔跑到机房

拿到数据正准备测试,结果机房 DNS 锅了

看了一下发现 php-fpm 服务挂了

修复了之后开始评测,然后在大屏上直播

感觉还可以,评测期间基本上就是在骂测了 1min + 但是却 0 pts 的憨憨

Day +16

想了想,还是有想停课冲冬令营的想法

稍作思考也许就会出结果了吧…

回去文化课实际上感觉还可以,基本上也都听得懂

勉强在班里还算可以,不过在这个学校里想要上一中必须得很靠前啊…

一点小小的总结

今年可能比较去年可能会更加迷茫一些

https://blog.woshiluo.com/900.html

去年的问题有一条今年还有的

  • 时间规划有一定问题

除此之外,能察觉到的主观问题还有

  • 思想方向有些许问题
  • 过于追梦,导致检查和部分暴力点未能做到

以下是一些客观原因

  • 提高组和入门组一起考太痛苦了,敲到最后在考场上不想写 值得一提的是,相似问题也在第一轮认证时有出现
  • 某名的感觉体力不太行…考试到最后手一直在冷(也有可能是七十中实在是太冷了)

顺带一提,我和同省大爷 StudyingFather 的意见一样

个人感觉我们今年的培训题目还是太偏了,考试虽然一直都在考,但是留于改题与总结的时间并不算长

不过我们也确实做不到跟上出题趋势这个大方向

希望我们会走的更好吧

「Jump up HIGH!!」

– Aqours

今年已经是我第三年学习 Oi 了

也许自己真的在实现最初的梦想

当时刚学 Oi 的时候,就一直在想,要是我能拿到 XJ 的第二块 Au 就好了

后来目标渐渐变了,变成很多奇奇怪怪的东西

回过头来,却发现自己也无意识中接近了最初的目标

不过还是很遥远就是了

不过人好歹还是要有梦想的,毕竟自己文化课也不算优秀

所以说,就当是有梦想了吧

虽然自己菜的真实

「私たち、 輝きたい!」

「LoveLive!SunShine!!」

Woshiluo
2019/12/04
乌鲁木齐市第一中学 小机房