新生赛div2

A

我们观察题目数据可知 \(1\le n\le 100\),所以我们只需要用 \(O(n^2)\) 的暴力枚举前 \(i\) 只小鱼的可爱程度判断累加即可。

#include<iostream>
using namespace std;
int n,m,x,y,l,k,h,g,f,d,s=0,p=0,ss=1,pp=1;
int a[110],b[110];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++){
	   for(int j=1;j<=i;j++){
	   	if(a[i]>a[j]) b[i]++;
	   }
	}
	for(int i=1;i<=n;i++) cout<<b[i]<<" ";
	return 0;
}

B

我们定义一个数列 \(\{a_n\}\) 的前缀和为 \(S_n = \sum_{i=1}^{n} a_i = a_1 + a_2 + \cdots + a_n\)

有了前缀和之后,我们可以使用差分来进行静态的区间求和。具体而言,对于一个区间 \([l,r]\),区间的和

\[a_l + a_{l+1} + \cdots + a_r = S_r - S_{l-1}。 \]

证明的话直接展开,\(S_r = a_1 + a_2 + \cdots + a_{l-1} + a_l + a_{l+1} + \cdots + a_r\)\(S_{l-1} = a_1 + a_2 + \cdots + a_{l-1}\),这样 \(S_r - S_{l-1}\) 便等于 \(a_l + a_{l+1} + \cdots + a_r\),即所求的区间和了,预处理出前缀和,单次就是 \(O(1)\) 复杂度可以完成的事情了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int a[MAXN],s[MAXN],n,m;
int main()
{
    
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        s[i] = s[i - 1] + a[i];
    }
    cin >> m;
    for (int i = 1; i <= m; i++)
    {
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;
    }
    return 0;
}

C

\(A\cap B=\varnothing\)\(A\cup B=U\) 可知 \(B\) 就是 \(A\) 的补集,因此只需计数合法的 \(A\)。设 \(|A|=k\),则 \(|B|=n-k\)。条件 \(|A|\notin A\) 等价于 \(k\notin A\)\(|B|\notin B\) 等价于 \(n-k\in A\)。于是 \(A\) 必须同时包含 \(n-k\) 且不包含 \(k\)。当 \(n-k=k\)\(n=2k\) 时矛盾,故偶数时 \(k\neq n/2\)

固定一个合法的 \(k\ (1\le k\le n-1)\),除去 \(k\)\(n-k\) 两个元素后,还要从剩下的 \(n-2\) 个元素中选 \(k-1\) 个与 \(n-k\) 一起构成 \(A\),方案数为 \(\binom{n-2}{k-1}\)。对所有合法 \(k\) 求和:

  • \(n\) 为奇数,\(k\) 取遍 \(1\)\(n-1\),总数为 \(\sum_{k=1}^{n-1}\binom{n-2}{k-1}=2^{n-2}\)
  • \(n\) 为偶数,需去掉 \(k=n/2\) 的项,总数为 \(2^{n-2}-\binom{n-2}{n/2-1}\)
  • 特别地,\(n=1,2\) 时无合法方案,答案为 \(0\)

答案对 \(10^9+7\) 取模。预处理阶乘、阶乘逆元以及 \(2\) 的幂,即可 \(O(1)\) 回答每次询问。

#include <bits/stdc++.h>
using namespace std;
const int N = 1000000;
const int M = 1000000007;
long long f[N+2], v[N+2], p[N+2];
long long qp(long long a, long long b) 
{
    long long r = 1;
    while (b) {
        if (b & 1) r = r * a % M;
        a = a * a % M;
        b >>= 1;
    }
    return r;
}
void pc() {
    f[1] = 1;
    for (int i = 2; i <= N; i++)
        f[i] = f[i-1] * i % M;
    v[N] = qp(f[N], M-2);
    for (int i = N-1; i >= 1; i--)
        v[i] = v[i+1] * (i+1) % M;
}
void pp() {
    p[1] = 1;
    for (int i = 2; i <= N; i++)
        p[i] = p[i-1] * 2 % M;
}
long long s(int n) {
    if (n == 1||n==2) return 0;
    
    if (n % 2) return p[n-1];
    int m = n - 2, k = m / 2;
    return (p[n-1] - f[m] * v[k] % M * v[m - k] % M + M) % M;
}
int main() {

    pc(); pp();
    int T; cin >> T;
    while (T--) {
        int n; cin >> n;
        cout << s(n) << '\n';
    }
    return 0;
}

D

由于所有树经历的加法操作完全相同,我们可以维护一个全局偏移量 add,表示到目前为止所有操作 1 累计增加的树高。任意时刻一棵树的真实高度等于它的初始高度加上 add

  • 操作 2:砍掉真实高度 \(< y\) 的树,即 \(h_i + \text{add} < y\),等价于 \(h_i < y - \text{add}\)
  • 操作 3:砍掉真实高度 \(> y\) 的树,等价于 \(h_i > y - \text{add}\)

也就是说,砍树操作相当于在初始高度上划定了一个允许范围 \([L, R]\)。初始时 \(L = -\infty\)\(R = +\infty\)。每次操作 2 用 \(y - \text{add}\) 更新 \(L = \max(L, y - \text{add})\),操作 3 用 \(y - \text{add}\) 更新 \(R = \min(R, y - \text{add})\)。因为砍掉的都是不满足范围条件的高度,剩下的树在初始高度排序后必然构成一个连续区间

因此我们可以将所有初始高度排序(由于 \(h_i \le 10^7\),用计数排序达到线性时间),得到有序数组 \(s\),并预处理前缀和。在 \(s\) 上维护双指针 \(l, r\),表示当前剩余树的下标区间。当 \(L\) 变大时,右移 \(l\) 直到 \(s[l] \ge L\);当 \(R\) 变小时,左移 \(r\) 直到 \(s[r] \le R\)。指针总移动次数为 \(O(n)\)

处理查询时,记剩余树数量 \(\text{cnt} = r - l + 1\)(如果 \(l>r\) 则无树,输出 qwq):

  • 总和:当前高度和 \(= \left(\sum_{i=l}^r s[i]\right) + \text{cnt} \times \text{add}\),利用前缀和 \(O(1)\) 计算,最后对 \(998442553\) 取模。
  • 最矮高度\(s[l] + \text{add}\)
  • 最高高度\(s[r] + \text{add}\)
    注意 add 可能为负,取模时要先取正模。

最后需要输出剩余树在数轴上的位置(即输入顺序的编号减 1)。我们只需遍历原始高度数组,判断每个初始高度是否在 \([L, R]\) 内,若是则输出其位置。若没有剩余树,输出 qwq

由于 \(y\) 的范围与 add 累计值可能超出 64 位有符号整数,区间边界 \(L, R\) 以及比较时需使用 __int128。输入输出量巨大,需要使用较快的 IO 方式(如 fread/fwrite 或缓冲区)。

整体时间复杂度为 \(O(n + q + \max H)\),空间复杂度约 \(150\text{MB}\),完全满足题目限制。

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

const int N = 7000005, H = 10000005, MOD = 998442553;
int h[N], s[N], c[H];
long long p[N];
int n, m, q;
__int128 L = -1e30, R = 1e30;
long long add;
int l = 1, r;

const int B = 1 << 22;
char ib[B], ob[B];
int ip = B, op;

inline char gc() {
    if (ip == B) fread(ib, 1, B, stdin), ip = 0;
    return ib[ip++];
}
inline long long rd() {
    long long x = 0; bool f = 0; char ch = gc();
    while (ch < '0' || ch > '9') { if (ch == '-') f = 1; ch = gc(); }
    while (ch >= '0' && ch <= '9') x = x * 10 + (ch ^ 48), ch = gc();
    return f ? -x : x;
}
inline void pc(char ch) {
    if (op == B) fwrite(ob, 1, B, stdout), op = 0;
    ob[op++] = ch;
}
void wt(long long x) {
    if (x < 0) pc('-'), x = -x;
    if (x > 9) wt(x / 10);
    pc(x % 10 + '0');
}
void wq() { pc('q'); pc('w'); pc('q'); }
void ed() { fwrite(ob, 1, op, stdout); }

int main() {
    n = rd(); m = n + 1;
    int mx = 0;
    for (int i = 1; i <= m; ++i) {
        h[i] = rd();
        if (h[i] > mx) mx = h[i];
    }
    for (int i = 1; i <= m; ++i) ++c[h[i]];
    int idx = 1;
    for (int v = 1; v <= mx; ++v) {
        int cnt = c[v];
        for (int j = 0; j < cnt; ++j) s[idx++] = v;
    }
    for (int i = 1; i <= m; ++i) p[i] = p[i - 1] + s[i];
    r = m;
    q = rd();
    while (q--) {
        int op = rd();
        if (op == 1) {
            add += rd();
        } else if (op == 2) {
            __int128 t = (__int128)rd() - add;
            if (t > L) L = t;
            while (l <= r && s[l] < L) ++l;
        } else if (op == 3) {
            __int128 t = (__int128)rd() - add;
            if (t < R) R = t;
            while (l <= r && s[r] > R) --r;
        } else if (op == 4) {
            if (l > r) wq(), pc('\n');
            else {
                long long sum = (p[r] - p[l - 1]) % MOD;
                long long cnt = r - l + 1;
                long long ad = (add % MOD + MOD) % MOD;
                long long ans = (sum + cnt * ad % MOD) % MOD;
                wt(ans), pc('\n');
            }
        } else if (op == 5) {
            if (l > r) wq(), pc('\n');
            else {
                long long val = (s[l] + add) % MOD;
                if (val < 0) val += MOD;
                wt(val), pc('\n');
            }
        } else {
            if (l > r) wq(), pc('\n');
            else {
                long long val = (s[r] + add) % MOD;
                if (val < 0) val += MOD;
                wt(val), pc('\n');
            }
        }
    }
    int cnt = 0;
    for (int i = 1; i <= m; ++i) if (L <= h[i] && h[i] <= R) ++cnt;
    wt(cnt), pc('\n');
    if (!cnt) wq(), pc('\n');
    else {
        bool fi = 1;
        for (int i = 1; i <= m; ++i) {
            if (L <= h[i] && h[i] <= R) {
                if (!fi) pc(' ');
                wt(i - 1);
                fi = 0;
            }
        }
        pc('\n');
    }
    ed();
}
posted @ 2026-08-12 19:23  li_cat  阅读(9)  评论(0)    收藏  举报