『模拟赛』多校A层冲刺NOIP2024炼石计划23

Rank

懒得尝试

100 + 10 + 0 + 25 = 135pts,rk60

A. 排序

签。

比较好想的是按位找第一个相邻两数不同的二进制位,标记强制换/强制不换,每次求答案时扫一遍,如果矛盾输出 -1,否则计算强制换的位数的贡献之和输出。时间复杂度 \(\mathcal{O(n\log V)}\)

点击查看代码


#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int n, q;
int a[N];
int must[30], no[30];
namespace Wisadel
{
    inline int Wclac()
    {
        int res = 0;
        fu(i, 29, 0)
        {
            if(must[i] && no[i]) return -1;
            if(must[i]) res += (1 << i);
        }
        return res;
    }
    inline void Wupd(int x, int y, int v)
    {
        fu(i, 29, 0)
        {
            int z1 = (x >> i) & 1, z2 = (y >> i) & 1;
            if(!(z1 ^ z2)) continue;
            else if(z1) must[i] += v;
            else if(z2) no[i] += v;
            break;
        }
    }
    short main()
    {
        freopen("sort.in", "r", stdin), freopen("sort.out", "w", stdout);
        n = qr;
        fo(i, 1, n) a[i] = qr;
        fo(i, 1, n - 1) Wupd(a[i], a[i + 1], 1);
        q = qr;
        printf("%d\n", Wclac());
        fo(i, 1, q)
        {
            int x = qr, k = qr;
            if(x != 1) Wupd(a[x - 1], a[x], -1), Wupd(a[x - 1], k, 1);
            if(x != n) Wupd(a[x], a[x + 1], -1), Wupd(k, a[x + 1], 1);
            a[x] = k;
            printf("%d\n", Wclac());
        }
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// All talk and never answer

B. 交换

把序列看成排列,每轮操作可以理解成在序列上进行一次置换,置换是具有结合律的。

考虑当 \(n\ |\ m\) 时,每轮操作相同,由于置换具有结合律,我们可以用快速幂的方法求出执行完 \(\lfloor\frac{t}{n}\rfloor\) 轮操作后的排列,剩下暴力求解,复杂度 \((n+m)\log t\)

考虑一般情况时,我们操作完一轮后下一次操作的 \(a\) 的下标中 \(+i\) 与第一次的 \(+i\) 可能不相等,那么就会导致下次操作的起始点不同,怎么办呢?我们直接将它循环左移一定的位数使得二者的起始点相同,那么之后就可以重复这样的操作了。我们设一轮 \(m\) 次的置换操作为 \(M\),循环左移的操作为 \(L\),右移的操作为 \(R\),那么整个过程可以写为 \(MLMLM\cdots MLMR^{\lfloor\frac{t}{n}\rfloor-1}\),将 \(ML\) 看成一整次操作,仍然可以用快速幂求解,最后余数仍然暴力处理,总时间复杂度仍然是 \(\mathcal{O((n+m)\log t)}\) 的。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 1e5 + 5;
const int mod = 998244353;
ll n, m, t;
int a[N], b[N], c[N];
struct rmm
{
    int a[N];
    rmm operator * (rmm A) const
    {
        rmm ZC;
        fo(i, 0, n - 1) ZC.a[i] = a[A.a[i]];
        return ZC;
    }
} M, ans, L, R;
namespace Wisadel
{
    inline rmm Wqp(rmm x, ll y)
    {
        rmm res;
        fo(i, 0, n - 1) res.a[i] = i;
        while(y){if(y & 1) res = res * x; x = x * x; y >>= 1;}
        return res;
    }
    short main()
    {
        freopen("swap.in", "r", stdin), freopen("swap.out", "w", stdout);
        n = qr, m = qr, t = qr;
        fo(i, 0, n - 1) a[i] = qr, M.a[i] = ans.a[i] = i;
        fo(i, 0, m - 1) b[i] = qr, c[i] = qr;
        fo(i, 1, m) swap(M.a[(b[i % m] + i) % n], M.a[(c[i % m] + i) % n]);
        fo(i, 0, n - 1) L.a[i] = (i + m) % n, R.a[i] = (i - m % n + n) % n;
        ll zc = t / m;
        if(zc > 0) ans = ans * M, M = L * M, ans = ans * Wqp(M, zc - 1), ans = ans * Wqp(R, zc - 1);
        t %= m;
        fo(i, 1, t) swap(ans.a[(b[i] + i + zc * m) % n], ans.a[(c[i] + i + zc * m) % n]);
        fo(i, 0, n - 1) printf("%d ", a[ans.a[i]]);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// All talk and never answer

C. 计算

正解是 dp + 拉插。

D. 莫队

将答案分为散块(未被推平过)和整块计算,都可以通过离线扫描线求解。

萌熊常规饭堂。

切了 T1 之后就有点摆了,T2 静不下心推性质,只拿了最低档分,T3 猜假了第一档,T4 也就暴力。

状态有点离线不知道为啥。

下午体活打球再次被重击,这次好像是镜片,被压了之后直接划了一道,别样的还不让洗澡(

晚上还有 arc,可能真是在役最后一场了,所以改题先咕咕,切打且珍惜。


完结撒花~

image

posted @ 2024-11-23 19:55  Ratio_Y  阅读(77)  评论(5编辑  收藏  举报