The Preliminary Contest for ICPC Asia Xuzhou 2019

A What is better?

推不出来,写个程序打表,用扩展中国剩余定理合并,居然会溢出longlong,还好不会溢出__int128(赛后exit(-1)测试),实际证明溢出返回-1是不靠谱的,毕竟后面可以又把它搞小了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;

const int MAXK = 10 + 5;

void exgcd(lll a, lll b, lll &x, lll &y) {
    if(!b)
        x = 1, y = 0;
    else
        exgcd(b, a % b, y, x), y -= a / b * x;
}

lll inv(ll a, ll b) {
    lll x = 0, y = 0;
    exgcd(a, b, x, y);
    x = (x % b + b) % b;
    if(!x)
        x += b;
    return x;
}

int k;
lll c[MAXK], m[MAXK];

lll exCRT(int k) {
    lll c1, c2, m1, m2, t;
    for(int i = 2; i <= k; ++i) {
        m1 = m[i - 1], m2 = m[i], c1 = c[i - 1], c2 = c[i];
        t = __gcd(m1, m2);
        if((c2 - c1) % t != 0)
            return -1;
        m[i] = m1 / t * m2;
        if(m[i] <= 0)
            exit(-1);
        c[i] = inv(m1 / t, m2 / t) * ((c2 - c1) / t) % (m2 / t) * m1 + c1;
        c[i] = (c[i] % m[i] + m[i]) % m[i];
    }
    return c[k];
}

/*map<pair<int, int>, pair<bool, int> > M;

bool dfs(int id, int pre) {
    if(M.count({id, pre}))
        return M[ {id, pre}].first;
    if(pre == -1) {
        for(int i = 1; i < id; ++i) {
            if(dfs(id - i, i) == false) {
                M[{id, pre}] = {true, i};
                return true;
            }
        }
        M[{id, pre}] = {false, -1};
        return false;
    } else {
        int c = min(2 * pre, id);
        if(c == id) {
            M[{id, pre}] = {true, c};
            return true;
        }

        for(int i = 1; i <= c; ++i) {
            if(dfs(id - i, i) == false) {
                M[{id, pre}] = {true, i};);
                return true;
            }
        }
        M[{id, pre}] = {false, -1};
        return false;
    }
}*/

ll f[72 + 5];

int main() {
#ifdef local
    freopen("lyz.in", "r", stdin);
#endif // local
    /*for(int i = 2; i <= 100; ++i) {
        printf("i=%d", i);
        if(dfs(i, -1)) {
            printf(" WIN\n");
            printf(" TO TAKE %d\n", M[ {i, -1}].second);
        } else
            printf(" FAIL\n");
    }

    for(int j = 1; j <= 20; ++j) {
        for(int k = -1; k <= 20; ++k) {
            if(M.count({j, k})) {
                printf("(%d,%d) \n", j, k);
                if(M[ {j, k}].first == true) {
                    printf(" WIN\n");
                    printf(" TO TAKE %d\n", M[ {j, k}].second);
                } else {
                    printf(" FAIL\n");
                }
                puts("");
            }
        }
    }*/

    int k;
    scanf("%d", &k);
    bool suc = 1;
    for(int i = 1; i <= k; ++i) {
        ll tmp1, tmp2;
        scanf("%lld%lld", &tmp1, &tmp2);
        m[i] = tmp1;
        c[i] = tmp2;
        if(c[i] > 1e15) {
            suc = false;
        }
    }

    if(!suc) {
        puts("Tankernb!");
        return 0;
    }

    lll n = exCRT(k);
    if(n <= 1 || n > 1e15) {
        puts("Tankernb!");
        return 0;
    }
    f[1] = 2;
    f[2] = 3;
    for(int i = 3; i <= 72; ++i) {
        f[i] = f[i - 1] + f[i - 2];
        if(f[i] >= 1e15) {
            //cout<<"i="<<i<<endl;
            break;
        }
    }
    for(int i = 1; i <= 72; ++i) {
        if(n == f[i]) {
            puts("Lbnb!");
            return 0;
        }
    }
    puts("Zgxnb!");
    return 0;
}

B so easy

一开始1e6弄个set莽了两次,果断T了,事实证明平衡树的常数的确相比离散化是在是太大了。用个并查集维护,删除一个节点的时候,假如他没有被删除过,那么就把他指向他的下一个元素(无论他的下一个元素是不是被删了都可以),并且把这个元素设置为“删除”,下面参照非递归路径压缩并查集弄了一个非递归路径压缩,实测727ms还算可以。

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

inline int read() {
    int x = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9')
        ch = getchar();
    do {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    } while(ch >= '0' && ch <= '9');
    return x;
}

const int MAXN = 1e6;
int z[MAXN + 5], x[MAXN + 5];
int px[2 * MAXN + 5], xtop;

int nxt[2 * MAXN + 5];
bool vis[2 * MAXN + 5] = {};

inline int find(int i) {
    int cur = nxt[i];
    while(vis[cur]) {
        cur = nxt[cur];
    }
    while(nxt[i] != cur) {
        int t = nxt[i];
        nxt[i] = cur;
        i = t;
    }
    return cur;
}

int main() {
#ifdef local
    freopen("lyz.in", "r", stdin);
#endif // local
    int n = read(), q = read();
    xtop = 0;
    for(int i = 1; i <= q; ++i) {
        z[i] = read(), x[i] = read();
        px[++xtop] = x[i];
        if(z[i] == 1)
            px[++xtop] = x[i] + 1;
    }
    sort(px + 1, px + 1 + xtop);
    xtop = unique(px + 1, px + 1 + xtop) - (px + 1);
    for(int i = 1; i <= q; ++i)
        x[i] = lower_bound(px + 1, px + 1 + xtop, x[i]) - (px);

    for(int i = 1; i <= xtop; ++i)
        nxt[i] = i;

    for(int i = 1; i <= q; ++i) {
        if(z[i] == 1) {
            if(!vis[x[i]]) {
                vis[x[i]] = true;
                nxt[x[i]] = nxt[x[i] + 1];
                find(x[i]);
            }
        } else {
            int res = find(x[i]);
            printf("%d\n", px[res]);
        }
    }

}

J Random Access Iterator

一个逗逼签到题,根据期望的线性性蛮好推的,首先第一遍dfs算出最大深度和各个节点的深度(虽然各个节点的深度是不必要的),第二遍dfs把dp数组算出来。设dp[i]表示i的子树给出最大深度的概率。那么对于深度为最大深度的叶子节点,dp[i]=1,其他叶子dp[i]=0。那么对于中间节点,它的所有k个子节点能提供最大深度的概率的期望就是各个子节点的dp值的平均值。它不能给出正确深度的概率就是这个期望的补数连续乘k次。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MOD = 1e9 + 7;

const int MAXN = 1e6;
vector<int> G[MAXN + 5];

int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

int dp[MAXN + 5];

int MAXD;

void dfs1(int u, int p, int d) {
    MAXD = max(MAXD, d);
    for(auto v : G[u]) {
        if(v != p) {
            dfs1(v, u, d + 1);
        }
    }
    return;
}

void dfs2(int u, int p, int d) {
    if(d == MAXD) {
        dp[u] = 1;
        return;
    }
    ll P = 0;
    int n = 0;
    for(auto v : G[u]) {
        if(v != p) {
            dfs2(v, u, d + 1);
            P += dp[v];
            ++n;
        }
    }
    P = P * qpow(n, MOD - 2) % MOD;
    ll Q = (1ll - P + MOD) % MOD;
    Q = qpow(Q, n);
    dp[u] = (1ll - Q + MOD) % MOD;
    return;
}

int main() {
#ifdef local
    freopen("lyz.in", "r", stdin);
#endif // local
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n - 1; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }

    dfs1(1, -1, 1);
    dfs2(1, -1, 1);

    printf("%d\n", dp[1]);
}

M Longest subsequence

设dp[i]表示匹配t串的长度为i的前缀需要用到s的最短长度,特别地为了统一,dp[0]=0,INF表示无法匹配。设pos[i][ch]表示在s串的i位置及其以后第一个ch出现的下标。

那么只有两种情况,第一,匹配了长度为i的前缀,然后从第i+1个字符开始严格大,i从0开始,这样就暴力一遍比t[i+1]大的最近的pos就行了。第二,完全匹配t,然后后面有多少加多少,注意至少要加一个

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 1e9;
const int MAXN = 1e6;
char s[MAXN + 5], t[MAXN + 5];
int dp[MAXN + 5];

int pos[MAXN + 5][26];

int main() {
#ifdef local
    freopen("lyz.in", "r", stdin);
#endif // local
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        scanf("%s%s", s + 1, t + 1);
        dp[0] = 0;
        for(int i = 1; i <= m; ++i)
            dp[i] = INF;
        for(int i = 1; i <= m; ++i) {
            for(int j = dp[i - 1] + 1; j <= n; ++j) {
                if(s[j] == t[i]) {
                    dp[i] = j;
                    break;
                }
            }
            if(dp[i] == INF)
                break;
        }

        for(int i = 0; i < 26; ++i)
            pos[n + 1][i] = INF;
        for(int i = n; i >= 1; --i) {
            for(int j = 0; j < 26; ++j)
                pos[i][j] = pos[i + 1][j];
            pos[i][s[i] - 'a'] = i;
        }

        int ans = -1;

        for(int i = 0; i <= m; ++i) {
            int last = INF;
            if(dp[i] == INF)
                break;
            else {
                if(i == m) {
                    if(dp[i] != n)
                        ans = max(ans, i + n - (dp[i] + 1) + 1);
                } else {
                    for(int j = t[i + 1] - 'a' + 1; j < 26; ++j)
                        last = min(last, pos[dp[i] + 1][j]);
                    ans = max(ans, i + n - last + 1);
                }
            }
        }
        printf("%d\n", ans);
    }
}

原文地址:https://www.cnblogs.com/Inko/p/11483758.html

时间: 2024-11-05 09:45:01

The Preliminary Contest for ICPC Asia Xuzhou 2019的相关文章

C:Dawn-K&#39;s water (The Preliminary Contest for ICPC Asia Shenyang 2019)

Dawn-K recently discovered a very magical phenomenon in the supermarket of Northeastern University: The large package is not necessarily more expensive than the small package. On this day, Dawn-K came to the supermarket to buy mineral water, he found

The Preliminary Contest for ICPC Asia Shenyang 2019

The Preliminary Contest for ICPC Asia Shenyang 2019 Texas hold'em Poker #include <bits/stdc++.h> using namespace std; const int maxn=1e6+10; int num[1000]; int shun(){ for (int i=15;i>=5;i--){ if (num[i]&&num[i-1]&&num[i-2]&&a

The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力)

The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力) 传送门:https://nanti.jisuanke.com/t/41400 题意: 给你三个数组a,b,c,要你求有多少个三元组(i,j,k),使得 \[ \begin{array}{l}{\left|A_{i}-B_{j}\right| \leq C_{k}, \text { and }} \\ {\left|B_{j}-C_{k}\right| \leq

The Preliminary Contest for ICPC Asia Shenyang 2019 H. Texas hold&#39;em Poker

题目链接:https://nanti.jisuanke.com/t/41408 题目意思很简单,就是个模拟过程. 1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <map> 6 #define rep(i,j,k) for(int i = (j); i <= (k); ++i) 7 #define

The Preliminary Contest for ICPC Asia Shenyang 2019 F. Honk&#39;s pool

题目链接:https://nanti.jisuanke.com/t/41406 思路:如果k的天数足够大,那么所有水池一定会趋于两种情况: ① 所有水池都是一样的水位,即平均水位 ② 最高水位的水池和最低水位的水池高度只相差一个高度,且最低水位一定是平均水位 如果k给了个限制: 我们当然需要先算出所有水池高度的平均值. 然后从低到高排序,二分小于平均值的水位,二分高于平均值的水位, 然后判断二分的预期值需要的天数是否小于等于k.然后二分找出最低水位的最大值, 最高水位的最小值,两者相减就是答案了

The Preliminary Contest for ICPC Asia Nanjing 2019/2019南京网络赛——题解

(施工中……) 比赛传送门:https://www.jisuanke.com/contest/3004 D. Robots(期望dp) 题意 给一个DAG,保证入度为$0$的点只有$1$,出度为$0$的点只有$n$. 现在一个机器人从$1$出发,每天都会以相同的概率前往相邻节点之一或静止不动. 每天机器人消耗的耐久等于经过的天数. 求机器人到点$n$期望消耗的耐久. 划水划的很愉快,唯一一道做出来的题.但是和题解做法不同(感觉我的方法麻烦),因此砸了3h在这题上面(正在试图读懂题解ing). 设

The Preliminary Contest for ICPC Asia Nanjing 2019 D. Robots(概率dp)

题目链接:https://nanti.jisuanke.com/t/41301 题目大意: 给定一个没有循环的有向图,它从节点1开始,到节点n结束. 有一个机器人从1开始,每天都会以相同的概率前往相邻节点之一或静止不动.每天机器人的耐久性消耗量等于经过的天数. 请计算机器人到达节点n时的预期耐久性消耗量. 保证只有一个节点(节点1)的in-degree等于00,并且只有一个节点(节点n)的out-degree等于0.并且图中没有多个边缘. 解题思路: 设dp[i]为从i到达终点n的期望时间那么很

The Preliminary Contest for ICPC Asia Shanghai 2019

D. Counting Sequences I 暴力搜索. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int MOD = 1000000007; map<vector<short>, short> m; vector<short> vec; void calc(int num1) { vector<short> tmp; if(num1) t

Digit sum-----The Preliminary Contest for ICPC Asia Shanghai 2019

A digit sum S_b(n)Sb?(n) is a sum of the base-bb digits of nn. Such as S_{10}(233) = 2 + 3 + 3 = 8S10?(233)=2+3+3=8, S_{2}(8)=1 + 0 + 0 = 1S2?(8)=1+0+0=1, S_{2}(7)=1 + 1 + 1 = 3S2?(7)=1+1+1=3. Given NN and bb, you need to calculate \sum_{n=1}^{N} S_b