Codeforces Round #536 (Div. 2)

目录

  • Codeforces Round #536 (Div. 2)

    • A

      • 题目大意
      • 题解
      • 卡点
      • C++ Code:
    • B
      • 题目大意
      • 题解
      • 卡点
      • C++ Code:
    • C
      • 题目大意
      • 题解
      • 卡点
      • C++ Code:
    • D
      • 题目大意
      • 题解
      • 卡点
      • C++ Code:
    • E
      • 题目大意
      • 题解
      • 卡点
      • C++ Code:
    • F
      • 题目大意
      • 题解
      • 卡点
      • C++ Code:

Codeforces Round #536 (Div. 2)

A

题目大意

给你一个\(n\times n(n\leqslant500)\)的矩阵,只包含.X,问最多可以找到多少个\(cross\),一个\(cross\)为如下图形:

X_X
_X_
X_X

_表示可以为任意字符。不同的\(cross\)之间可以重叠

题解

可以枚举中间X,判断是否合法

卡点

C++ Code:

#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define maxn 510

int Tim, n, m, ans;
char s[maxn][maxn];
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%s", s[i] + 1);
    }
    for (int i = 2; i < n; ++i) {
        for (int j = 2; j < n; ++j) if (s[i][j] == 'X') {
            if (s[i - 1][j - 1] == 'X' && s[i + 1][j - 1] == 'X'
                    && s[i - 1][j + 1] == 'X' && s[i + 1][j + 1] == 'X') ++ans;
        }
    }
    printf("%d\n", ans);
    return 0;
}

B

题目大意

有\(n(n\leqslant10^5)\)道菜,第\(i\)道菜有\(a_i\)份,每个价值都为\(c_i\)。有\(m(m\leqslant10^5)\)个顾客,第\(i\)个顾客要\(d_i\)份第\(t_i\)种菜(只有第\(i\)个顾客走后第\(i+1\)个顾客才会来)。餐厅按如下规则给菜(一份菜一份菜给):

  1. 若当前有第\(t_i\)种菜,就给该顾客一份
  2. 若没有第\(t_i\)种菜,就给该顾客最便宜的菜,若有多个最便宜的菜,给编号最小的
  3. 若没有菜,顾客会愤怒的离开

若该顾客没有愤怒的离开,输出餐厅给的菜的价值总和,若离开了,输出\(0\)(注意,已经给这个顾客的菜依然给了这个顾客,也就是说无法回收菜)

题解

原来的题目中似乎没有注意部分,导致我以为是线段树上二分,然后不想写,先写了\(C\)和\(D\),然后出题人发公告。于是变成了真正的\(B\)题难度。

只需要记录一下价值最小的没有被用完的菜就行了,直接模拟即可,发现一道菜只会被用完一次,所以复杂度是\(O(n+m)\)的

卡点

C++ Code:

#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define maxn 100010

int Tim, n, m, lst;
long long a[maxn], c[maxn];
int ret[maxn], rnk[maxn];
int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    std::cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        std::cin >> a[i];
    }
    for (int i = 1; i <= n; ++i) {
        std::cin >> c[i];
        rnk[i] = i;
    }
    std::sort(rnk + 1, rnk + n + 1, [] (int a, int b) { return c[a] < c[b]; });
    for (int i = 1; i <= n; ++i) ret[rnk[i]] = i;
    lst = 1;
    while (m --> 0) {
        long long t, d, ans = 0;
        std::cin >> t >> d;
        if (a[t] >= d) {
            a[t] -= d;
            std::cout << d * c[t] << '\n';
            continue;
        }
        ans = a[t] * c[t];
        d -= a[t];
        a[t] = 0;
        for (int i; lst <= n; ++lst) {
            i = rnk[lst];
            if (a[i] >= d) {
                ans += d * c[i];
                a[i] -= d;
                d = 0;
                std::cout << ans << '\n';
                break;
            }
            ans += a[i] * c[i];
            d -= a[i];
            a[i] = 0;
        }
        if (d) std::cout << "0\n";
    }
    return 0;
}

C

题目大意

有\(n(n\leqslant3\times10^5)\)个数,保证\(n\)为偶数,要把它们分成若干组,每组至少两个数。假设分成\(m\)组,第\(i\)组的和为\(s_i\),要求最小化\(\sum\limits_{i=1}^ms_i^2\)

题解

发现一定是每组两个数,因为把两个总和分别为\(a,b\)的组合起来的时候,代价从\(a^2+b^2\)变为了\(a^2+2ab+b^2\)肯定不优秀。继续发现要让\(\max\{s_i\}\)最小,于是排一个序,每次取最小和最大的放为一组即可。

卡点

C++ Code:

#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define maxn 300010

int Tim, n, m;
int s[maxn];
long long ans;
int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0);
    std::cin >> n;
    for (int i = 0; i < n; ++i) std::cin >> s[i];
    std::sort(s, s + n);
    const int nn = n >> 1;
    for (int i = 0, x; i < nn; ++i) {
        x = s[i] + s[n - i - 1];
        ans += x * x;
    }
    std::cout << ans << std::endl;
    return 0;
}

D

题目大意

给你一张\(n(n\leqslant10^5)\)个点\(m(m\leqslant10^5)\)条边的无向图,现在在点\(1\),每次到一个没有经过过的点就把那个点记录下来,直到经过所有\(n\)个点,问最后记录下的序列最小的字典序是什么,可以重复经过点和边。

题解

这可比\(NOIP2018D2T1\)简单多了,只需要求一个一个类似最小生成树的东西就行了。用一个小根堆记录当前经过过的点可以到达的没有经过过的点,每次取出堆顶,把与它相连的点加入堆即可。

卡点

C++ Code:

#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define maxn 100010
int head[maxn], cnt;
struct Edge {
    int to, nxt;
} e[maxn << 1];
inline void addedge(int a, int b) {
    e[++cnt] = (Edge) { b, head[a] }; head[a] = cnt;
    e[++cnt] = (Edge) { a, head[b] }; head[b] = cnt;
}

int Tim, n, m;
std::priority_queue<int, std::vector<int>, std::greater<int> > q;
bool inq[maxn];
int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    std::cin >> n >> m;
    for (int i = 0, a, b; i < m; ++i) {
        std::cin >> a >> b;
        addedge(a, b);
    }
    q.push(1);
    inq[1] = true;
    for (int Tim = 1; Tim < n; ++Tim) {
        int u = q.top(); q.pop();
        std::cout << u << ' ';
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (!inq[v]) {
                q.push(v);
                inq[v] = true;
            }
        }
    }
    std::cout << q.top() << std::endl;
    return 0;
}

E

题目大意

有\(n(n\leqslant10^5)\)个时间点,分别为\(1\sim n\),有\(k(k\leqslant10^5)\)个红包,第\(i\)个红包可以在\([s_i,t_i]\)内领取,有钱\(w_i\),领了这个红包,直到\(d_i\)时间点之后(不包含\(d_i\))才可以领取下一个红包。

\(Bob\)按如下规则领红包:

  1. 领当前可以领的最大的红包
  2. 若有多个,领\(d\)最大的红包
  3. 若还有多个,随机领一个

\(Alice\)希望\(Bob\)领的最少,她可以在最多\(m(m\leqslant200)\)个时间点打扰\(Bob\),使得他不能领红包,问\(Bob\)最少领到多少钱

题解

还没写

卡点

还没写

C++ Code:


F

题目大意

有一串\(n(n\leqslant10^9)\)个数的数列,给你\(b_1\sim b_k(k\leqslant100)\)。当\(i>k\)时:
\[
f_i=(\prod\limits_{i=1}^kf_{i-j}^{b_i})\bmod{998244353}
\]
已知\(f_1=f_2=\cdots=f_{k-1}=1,f_n=m\),问最小的正整数\(f_k\)可能是多少

题解

写一下式子,发现可以用矩阵快速幂求出\(f_n=f_k^x\bmod{998244353}\)中的\(x\)(幸好这道题不需要线性齐次递推,不然玩完),复杂度\(O(k^3\log_2n)\)。

接下来就是求\(f_k^x\equiv m\pmod{998244353}\)
\[
x\ln(f_k)\equiv\ln(m)\pmod{\varphi(998244353)}\\ln(f_k)\equiv\ln(m)x^{-1}\pmod{998244352}\f_k\equiv\exp(\ln(m)x^{-1})\pmod{998244353}\\]
但是\(x\)在\(\pmod{998244352}\)下可能没有逆元,怎么办呢?可以用\(exgcd\)求出\(\dfrac{\gcd(x,998244352)}x\),然后把\(\ln(m)\)除掉\(\gcd(x,998244352)\),若有余数则无解。

卡点

比赛结束后\(5min\)发现可以除掉\(\gcd\)来做,然后自闭

C++ Code:

#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
const int mod = 998244353, __mod = mod - 1;
#define maxn 105

int Tim, n, m, k;
int b[maxn];
struct Matrix {
    int s[maxn][maxn];
    inline Matrix operator * (const Matrix &rhs) const {
        Matrix res;
        for (int i = 0; i < k; ++i) {
            for (int j = 0; j < k; ++j) {
                long long t = 0;
                for (int l = 0; l < k; ++l) (t += static_cast<long long> (s[i][l]) * rhs.s[l][j]) %= __mod;
                res.s[i][j] = t;
            }
        }
        return res;
    }
} base, res;

namespace Math {
    std::map<int, int> mp;
    bool init = false;
    long long BSGS(long long y, long long z) {
        y %= mod, z %= mod;
        if (!y) return -1;
        long long tmp = 1, t = sqrt(mod - 1) + 1;
        if (!init) {
            mp.clear();
            for (int i = 0; i <= t; i++) {
                mp[tmp * z % mod] = i;
                if (i != t) tmp = tmp * y % mod;
            }
            init = true;
        }
        long long tmp6 = tmp;
        for (int i = 1; i <= t; i++) {
            if (mp.count(tmp6)) return i * t - mp[tmp6];
            tmp6 = tmp6 * tmp % mod;
        }
        return -1;
    }

    inline int pw(int base, int p) {
        static int res;
        for (res = 1; p; p >>= 1, base = static_cast<long long> (base) * base % mod) if (p & 1) res = static_cast<long long> (res) * base % mod;
        return res;
    }

    long long exgcd(long long a, long long b, long long &x, long long &y) {
        if (!b) {
            x = 1, y = 0;
            return a;
        }
        long long t = exgcd(b, a % b, y, x);
        y -= a / b * x;
        return t;
    }
    long long retgcd;
    long long inv(long long a) {
        long long x, y;
        retgcd = exgcd(a, __mod, x, y);
        return (x % __mod + __mod) % __mod;
    }
}

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    std::cin >> k;
    for (int i = 0; i < k; ++i) std::cin >> base.s[i][0];
    for (int i = 1; i < k; ++i) base.s[i - 1][i] = 1;
    res.s[0][0] = 1;
    std::cin >> n >> m;
    for (n -= k; n; n >>= 1, base = base * base) if (n & 1) res = res * base;
    const long long y = res.s[0][0];
    long long lnz = Math::BSGS(3, m);
    long long t = Math::inv(y);
    if (lnz % Math::retgcd) {
        puts("-1");
        return 0;
    }
    lnz = lnz / Math::retgcd * t % __mod;
    std::cout << Math::pw(3, lnz) << '\n';
    return 0;
}

原文地址:https://www.cnblogs.com/Memory-of-winter/p/10345347.html

时间: 2024-08-01 14:15:54

Codeforces Round #536 (Div. 2)的相关文章

Codeforces Round #536 (Div. 2) - D. Lunar New Year and a Wander(最短路)

Problem  Codeforces Round #536 (Div. 2) - D. Lunar New Year and a Wander Time Limit: 3000 mSec Problem Description Input Output Output a line containing the lexicographically smallest sequence a1,a2,…,an Bob can record. Sample Input 3 21 21 3 Sample

Codeforces Round #536 (Div. 2) E dp + set

https://codeforces.com/contest/1106/problem/E 题意 一共有k个红包,每个红包在\([s_i,t_i]\)时间可以领取,假如领取了第i个红包,那么在\(d_i\)后才能领取下一个红包,每个红包价值\(w_i\),对方假如有机会领取红包他一定会领取,你有m次阻止对方领取的机会,问对方最少可以拿到多少红包 题解 定义dp[i][j]为前i秒用了j次机会让对方拿到最小价值的红包 \(dp[i][j] - > dp[i+1][j+1]\) 假如使用阻止 \(d

Codeforces Round #536 (Div. 2) B. Lunar New Year and Food Ordering

#include <bits/stdc++.h> #define N 300010 #define PII pair<int, int> using namespace std; typedef long long LL; int n, m, a[N], c[N], t, d; LL ans = 0; priority_queue<PII, vector<PII>, greater<PII> > Q; int main(){ scanf(&quo

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除

Codeforces Round #339 (Div. 2) B. Gena&#39;s Code

B. Gena's Code It's the year 4527 and the tanks game that we all know and love still exists. There also exists Great Gena's code, written in 2016. The problem this code solves is: given the number of tanks that go into the battle from each country, f