NEFU 9.28

A.The Artful Expedient

题意

首先定义一个整形变量n,Koyomi和Karen都会分别选择n个不同的正整数,分别表示为X1,X2,…Xn和Y1,Y2,…Yn。它们不断重复显示它们的序列,并一直重复直到所有2n个整数变得不同,此时,这是唯一被保留和考虑的最终状态。 他们需要计算满足有序数对(i,j)[1<=i,j<=n]中(Xi ^ Yi)的值等于2n个整数之中任意一个整数的值的有序数对的数量。

如果这样的配对数量是偶数时,Karen就可以取得胜利,否则Koyomi胜利。你需要帮助他们决出最近一场比赛的获胜者。

思路

题目中没有说这n个数为1~n,故要用map存这些数,然后计算两两的异或值,并去map中寻找是否存在。

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-09-28 19:49:35
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-09-28 20:03:49
 * @FilePath: \Icey_dying\competition\2021\2021.09\2021.9.28\A.cpp
 */
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int n;
int a[N], b[N];
map<int, int> m;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i], m[a[i]]++;
    for (int i = 1; i <= n; i++)
        cin >> b[i], m[b[i]]++;
    int cnt = 0, ans;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            ans = a[i] ^ b[j];
            if (m[ans]) {
                cnt++;
                // cout << ans << endl;
            }
        }
    }
    // cout << cnt << endl;
    if (!(cnt % 2))
        cout << "Karen\n";
    else
        cout << "Koyomi\n";
    return 0;
}

B.The Eternal Immortality

题意

给出a,b,求 b ! a ! \frac{b!}{a!} a!b!的个位数

思路

如果a,b跨越0,则为0;如果没有直接连乘计算即可

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-09-28 20:07:54
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-09-28 20:12:45
 * @FilePath: \Icey_dying\competition\2021\2021.09\2021.9.28\B.cpp
 */
#include <bits/stdc++.h>
using namespace std;

int main()
{
    long long a, b;
    cin >> a >> b;
    if (a == b)
        cout << 1 << endl;
    else if (a % 10 >= b % 10 || b - a >= 10)
        cout << 0 << endl;
    else {
        int aa = a % 10;
        int bb = b % 10;
        int ans = 1;
        for (int i = aa + 1; i <= bb; i++)
            ans = ans * i % 10;
        cout << ans << endl;
    }
    return 0;
}

C.The Intriguing Obsession

题意

海上有三个区域,每个区分别有a,b,c个岛屿.
火怜和月火现在想要在区与区之间建设桥梁,但是有如下限制.
1:同一个区的两个岛之间不连通或者连通且最短距离不小于3
2:每一座桥的距离假设都为1
问:一共有多少种不同的建桥方法,桥的数量可以是任意的合法的数量。
a,b,c<=5000.最后取模998244353.

思路

首先我们来看.同一个区域中的两个点之间绝对不能造桥.
同理如果一个区域中两个点同时连了另一个区域的同一个点也是不行的.
那么根据抽屉原理,两个区域中要想连边,这两个区域中选择的点的数量必须要相同.
那么接下来就是从两个区域中每次找出i个点来,求一下组合 C a i × C b i C_a^i\times C_b^i Cai×Cbi.
然后两个区域找出来的i个点之间可以随意相连,连法一共 i ! i! i!种.
所以a,b两个区域之间相连的办法有 C a i × C b i × i ! C_a^i\times C_b^i\times i! Cai×Cbi×i!种.

再看三个区域之间相连,你会发现只要不进行上面两种操作,不可能会出现不合法的情况.
那么这样,a与b,b与c,c与a之间的连线都是互不干扰的,可以分别计算.
设a,b之间相连的办法为tc,b,c之间相连的办法为ta,a,c之间相连的办法为tb.
则答案就是 ( t a × t b × t c ) (ta\times tb\times tc) (ta×tb×tc).
数据范围是5000,可以用杨辉三角预处理组合数,也可以用阶乘逆元,这个就看你自己了.

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-10-04 09:53:08
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-10-04 10:02:10
 * @FilePath: \Icey_dying\competition\2021\2021.09\2021.9.28\C.cpp
 */
#include <bits/stdc++.h>
typedef long long ll;
const ll mod = 998244353;
const ll maxn = 5000 + 7;
using namespace std;
int Fac[maxn * 2], Inv[maxn * 2];

void Prepare()
{
    Fac[0] = 1;
    for (int i = 1; i <= maxn; i++)
        Fac[i] = 1ll * Fac[i - 1] * i % mod;
    Inv[0] = Inv[1] = 1;
    for (int i = 2; i <= maxn; i++)
        Inv[i] = mod - 1ll * (mod / i) * Inv[mod % i] % mod;
    for (int i = 2; i <= maxn; i++)
        Inv[i] = 1ll * Inv[i - 1] * Inv[i] % mod;
}

inline ll C(int u, int v)
{
    if (u < 0 || v < 0 || u < v)
        return 0;
    return 1ll * Fac[u] * Inv[v] % mod * Inv[u - v] % mod;
}
int a, b, c;
int main()
{
    Prepare();
    cin >> a >> b >> c;
    ll ta, tb, tc;
    ta = tb = tc = 0;
    for (int i = 0; i <= min(a, b); i++) {
        ta = (ta + C(a, i) * C(b, i) % mod * Fac[i] % mod) % mod;
    }
    for (int i = 0; i <= min(a, c); i++) {
        tb = (tb + C(a, i) * C(c, i) % mod * Fac[i] % mod) % mod;
    }
    for (int i = 0; i <= min(b, c); i++) {
        tc = (tc + C(b, i) * C(c, i) % mod * Fac[i] % mod) % mod;
    }
    cout << ta * tb % mod * tc % mod << endl;
    return 0;
}

E.The Untended Antiquity

题意

给一个n∗m(0<=n,m<=2500)的空地,支持三种操作:

在以(x1,y1)为左上角,(x2,y2)为右下角的矩形外侧建一堵墙…(不会盖到空地的最外围)

拆除以(x1,y1)为左上角,(x2,y2)为右下角的矩形外侧的墙…(墙保证存在)

查询(x1,y1)格与(x2,y2)格是否连通= = 其中,墙围保证没有公共点…

思路

首先,两个点肯定要被围在同样的围墙中,否则两个点显然无法互相到达。

明确了这个事实,我们来看看这道题。

不妨把建墙看成二维区间加,拆墙看成二维区间减,把判断两个点是否被围在同样的围墙中看成判断这两个点的值是否相同。这个过程可以用二维树状数组解决。

但是,新的问题又出现了:区间加什么?从 1 1 1开始逐个加显然不行,因为 2 + 3 = 1 + 4 2+3=1+4 2+3=1+4,如果一个点被墙 2 , 3 2,3 2,3围住,另一个点被墙 1 , 4 1,4 1,4围住,那么这两个点就会被判为可以互相到达,但是这两个点显然是无法互相到达的。

方法是把一个操作看成一个 B A S E BASE BASE进制数,每次加上这个数。这样重复的概率比较小。

代码

/*
 * @Author: Icey_dying
 * @Date: 2021-10-04 10:41:27
 * @LastEditors: Icey_dying
 * @LastEditTime: 2021-10-04 10:49:00
 * @FilePath: \Icey_dying\competition\2021\2021.09\2021.9.28\E2.cpp
 */
#include <bits/stdc++.h>
using namespace std;
const int N = 2505;
const int BASE = 666;
int tree[N][N];
int n, m, q;
int lowbit(int x) { return x & -x; }
void add(int x, int y, int k)
{
    for (int i = x; i <= n; i += lowbit(i)) {
        for (int j = y; j <= m; j += lowbit(j)) {
            tree[i][j] += k;
        }
    }
}
int query(int x, int y)
{
    int sum = 0;
    for (int i = x; i > 0; i -= lowbit(i)) {
        for (int j = y; j > 0; j -= lowbit(j)) {
            sum += tree[i][j];
        }
    }
    return sum;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m >> q;
    int op, x1, x2, y1, y2;
    while (q--) {
        cin >> op >> x1 >> y1 >> x2 >> y2;
        if (op == 1) {
            int k = x1 * BASE * BASE * BASE + y1 * BASE * BASE + x2 * BASE + y2;
            add(x1, y1, k);
            add(x1, y2 + 1, -k);
            add(x2 + 1, y1, -k);
            add(x2 + 1, y2 + 1, k);
        } else if (op == 2) {
            int k = x1 * BASE * BASE * BASE + y1 * BASE * BASE + x2 * BASE + y2;
            add(x1, y1, -k);
            add(x1, y2 + 1, k);
            add(x2 + 1, y1, k);
            add(x2 + 1, y2 + 1, -k);
        } else {
            if (query(x1, y1) == query(x2, y2))
                cout << "Yes\n";
            else
                cout << "No\n";
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值