2020 CCPC-Wannafly Winter Camp Day1 总结

部分题目列表:

题号题目算法
B题密码学签到题,字符串处理
H题最大公约数数学、gcd、大数
F题乘法较为巧妙的使用二分
A题期望逆序对-
C题染色图-
I题K小数查询在线线段树套权值线段树

B题 密码学

签到题,就是一个字符串的计算,可耻的WA了一发是因为忘记了解码要倒着去解( i i i m m m 0 0 0)

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

const int maxn = 1005;
int a[maxn], b[maxn];
string str[maxn];
int s[maxn][105];

void dde(int k)
{
    for (int i = 0; i < str[k].size(); i++) {
        if (str[k][i] > 'Z')
            s[k][i] = str[k][i] - 'a';
        else
            s[k][i] = str[k][i] - 'A' + 26;
    }
}

int main(void)
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++)
        scanf("%d%d", &a[i], &b[i]);
    for (int i = 1; i <= n; i++)
        cin >> str[i];
    
    for (int i = m - 1; i >= 0; i--) {
        int x = a[i], y = b[i];
        string aa = str[x], bb = str[y];
        while (str[x].size() < str[y].size())
            str[x] = str[x] + str[x];
 
        for (int j = 0; j < str[y].size(); j++) {
            dde(x), dde(y);
            int kkk = s[y][j] - s[x][j];
            kkk = (kkk + 52) % 52;
            if (kkk < 26)
                bb[j] = kkk + 'a';
            else
                bb[j] = kkk - 26 + 'A';
        }

        str[x] = aa;
        str[y] = bb;
    }

    for (int i = 1; i <= n; i++)
            cout << str[i] << endl;
    return 0;
}

H题 最大公约数

Java大数走起

题干:有三个人 A , B , C A,B,C A,B,C,其中 A A A B B B 共享了一个神秘的数字 k k k,已知 1 ≤ k ≤ n 1≤k≤n 1kn, 现在 A A A C C C 说:“ k k k 的值等于 x x x”。
C C C 不太信任 A A A,于是想向 B B B 确认一下 k k k 是否真的等于 x x x B B B 虽然不想直接把 k k k 的值告诉 C C C,但是 B B B 允许 C C C 给出一个正整数 y y y(注意 y y y 可以大于 n n n),然后 B B B 会回答 g c d ( k , y ) gcd(k,y) gcd(k,y)
现在给出 k , n k,n k,n,你需要帮助 C C C 决定这样的 y y y 的取值,使得 C C C 一定可以通过 B B B 的回答来判断 A A A 有没有撒谎。如果这样的 y y y 有多个,你需要输出最小的那个。

输入第一行是一个整数 T ( 1 ≤ T ≤ 50 ) T(1≤T≤50) T(1T50)
对于每组数据,输入一行两个整数 n , k ( 1 ≤ k ≤ n ≤ 500 ) n,k(1≤k≤n≤500) n,k(1kn500)

对于每组数据,输出一行一个整数,表示答案。如果满足条件的 y y y 不存在,则输出 −1。

// package Main;
import java.util.*;
import java.math.*;
public class Main {
    static BigInteger arr[] = new BigInteger[505];
    static BigInteger m(int a) {
        return new BigInteger(a + "");
    }
    static boolean isP(int x) {
        for (int i = 2; i * i <= x; i++) 
            if (x % i == 0) 
                return false;
        return true;
    }
    static void init() {
        arr[1] = BigInteger.ONE;
        for (int i = 2; i <= 500; i++) {
            if (isP(i)) 
                arr[i] = arr[i - 1].divide(arr[i - 1].gcd(m(i))).multiply(m(i));
            else 
                arr[i] = arr[i - 1];
        }
    }
    public static void main(String[] args) {
        init();
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        while (t-- != 0) {
            int n = sc.nextInt();
            int k = sc.nextInt();
            BigInteger ans = arr[n / k].multiply(m(k));
            System.out.println(ans);
        }
    }
}

F题 乘法

题意:给出一个长度为 n n n 的数列和一个长度为 m m m 的数列, 可以构造得到一个 n × m n×m n×m 的矩阵 C C C,其中 C i , j = A i × B j C_{i,j}=A_{i}×B_{j} Ci,j=Ai×Bj, 给出整数 K K K,你需要求出 C C C 中第 K K K 大的数的值。( 1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^{5} 1n,m105, 1 ≤ K ≤ n × m 1≤K≤n×m 1Kn×m)

思路:二分的找,需要额外注意当数为负数和零时候的情况

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

#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef long long ll;
const int maxn = 1e5 + 5;

ll ef = 1e12;
ll n, m, k;
vector<ll> a, b;

ll update_a(ll x, ll mid, ll l, ll r)
{
    if (l == r)
        return l;
    int m = (l + r + 1) >> 1;
    if (x * b[m] <= mid)
        return update_a(x, mid, m, r);
    else
        return update_a(x, mid, l, m - 1);
}

ll update_b(ll x, ll mid, ll l, ll r)
{
    if (l == r)
        return l;
    int m = (l + r) >> 1;
    if (x * b[m] <= mid)
        return update_b(x, mid, l, m);
    else
        return update_b(x, mid, m + 1, r);
}

ll Binary_Search(ll l, ll r) 
{
    if (l == r)
        return l;
    ll mid = (l + r) >> 1;

    ll ans = 0;
    for (int i = 0; i < a.size(); i++) {
        if (a[i] < 0)
            ans += m - update_b(a[i], mid, 0, b.size());
        else
            ans += update_a(a[i], mid, -1, b.size() - 1) + 1;
    }

    if (ans >= k)
        return Binary_Search(l, mid);
    else
        return Binary_Search(mid + 1, r);
}

int main(void)
{
    IO;
    cin >> n >> m >> k;
    k = n * m - k + 1;

    ll tmp;
    for (int i = 0; i < n; i++) {
        cin >> tmp;
        a.push_back(tmp);
    }
    for (int i = 0; i < m; i++) {
        cin >> tmp;
        b.push_back(tmp);
    }
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());

    cout << Binary_Search(-ef, ef) << endl;

    return 0;
}

A题 期望逆序对

题意:生成一个每个数 a i a_{i} ai是从 [ l i , r i ] [l_{i}, r_{i}] [li,ri] 中生成的整数, a a a 中不存在相同的数字,求逆序对个数的期望的最小值, 数组范围至 5 e 3 5e3 5e3.
输出一行一个整数,表示答案对 998244353 取模后的值。假设答案的最简分数表示是 a b \frac{a}{b} ba, 你需要输出一个整数 k k k 满足 x × y ≡ x    m o d    998244353 x \times y \equiv x \; mod \;998244353 x×yxmod998244353

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

const int mod = 998244353;
const int maxn = 5050;

struct section {
    int l, r;
    void read() {
        scanf("%d%d", &l, &r);
    }
    bool operator < (const section& s1) {
        return l + r < s1.l + s1.r;
    }
}a[maxn];

int n, b[maxn];

int quick(int x, int y)
{
    int z = 1;
    while (y) {
        if (y & 1)
            z = 1ll * z * x % mod;
        y >>= 1;
        x = 1ll * x * x % mod;
    }
    return z;
}

int cal(section x, section y)
{
    int l = max(x.l, y.l);
    if (l > x.r)
        return 0;
    int r = min(x.r, y.r);
    int ans = 1ll * (l - y.l + r - y.l) * (r - l + 1) / 2 % mod;
    ans = (ans + 1ll * (x.r - r) * (y.r - y.l + 1)) % mod;
    return ans;
}

int main(void)
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        a[i].read();
    sort(a + 1, a + n + 1);

    int ans = 0;
    for (int i = 1; i <= n; i++)
        b[i] = quick(a[i].r - a[i].l + 1, mod - 2);

    for (int i = 1; i <= n; i++)
        for (int j = i + 1; j <= n; j++)
            ans = (ans + 1ll * b[i] * b[j] % mod * cal(a[i], a[j])) % mod;

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

C题 染色图

—待补—

I题 K小数查询

树套树之线段树套权值线段树,在线维护

—待补—

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值