【题解】NOIP 13连测 #2

NOIP 13连测 #2

A

手动模拟可以发现:

ai2,ai,ai+2 总是相邻的,且 a1,a2 是相邻的,an 在最左端

  • n 为奇数,答案为:anan2a1+a2a4an1
  • n 为偶数,答案为:anan2a2+a1a3an1

时间复杂度 O(n)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, a[N];
int main() {
    freopen("reverse.in", "r", stdin);
    freopen("reverse.ans", "w", stdout);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    if (n & 1){
        for (int i = n; i > 0; i -= 2)
            cout << a[i] << ' ';
        for (int i = 2; i <= n; i += 2)
            cout << a[i] << ' ';
    }
    else{
        for (int i = n; i > 0; i -= 2)
            cout << a[i] << ' ';
        for (int i = 1; i <= n; i += 2)
            cout << a[i] << ' ';
    }
    return 0;
}

B

如果一条边不在图中一棵最小生成树中,那么加入一条新边之后的新图中也可以不用考虑这条边了。(考虑kruskal将边排序的过程)

对原图使用 prim 求出最小生成树的 n1 条边,与新加入的 q 条边排序后,做次 q 次 kruskal 即可。

时间复杂度 O(n2+nqlogn)。(logn为并查集)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
int n, q, px[N], py[N], cnt, id[N];
bool vis[N];
ll d[N];
struct Edge{    
    int u, v, t;
    ll w;
    bool operator<(const Edge &tmp) const { return w < tmp.w; }
} e[N];
ll cal(int x) { return abs(1ll * x * x * x); }
ll dis(int u, int v) { return cal(px[u] - px[v]) + cal(py[u] - py[v]); }
void add(int u, int v, ll w, int t) { e[++cnt] = (Edge){u, v, t, w}; }
void prim(){
    memset(d, 0x3f, sizeof(d));
    d[1] = 0;
    for (int i = 1; i <= n; i++){
        int u = 0;
        for (int j = 1; j <= n; j++)
            if (!vis[j] && (!u || d[u] > d[j]))
                u = j;
        vis[u] = 1;
        if (id[u])
            add(u, id[u], d[u], 0);
        for (int j = 1; j <= n; j++)
            if (!vis[j] && d[j] > dis(u, j)){
                d[j] = dis(u, j);
                id[j] = u;
            }
    }
}
int fa[N];
ll ans;
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void solve(int t){
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    ans = 0;
    for (int i = 1; i <= cnt; i++){
        if (e[i].t > t)
            continue;
        int u = find(e[i].u), v = find(e[i].v);
        if (u != v){
            ans += e[i].w;
            fa[u] = v;
        }
    }
    cout << ans << '\n';
}
int main(){
    freopen("logistics.in", "r", stdin);
    freopen("logistics.ans", "w", stdout);
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        cin >> px[i] >> py[i];
    prim();
    for (int i = 1; i <= q; i++){
        ll w;
        int u, v;
        cin >> u >> v >> w;
        add(u, v, w, i);
    }
    sort(e + 1, e + cnt + 1);
    for (int i = 0; i <= q; i++)
        solve(i);
    return 0;
}

C

很水的题目,显然是排好序后答案最小。

当然也可以用 n

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 300010, P = 998244353;
int n, T;
int rk[N];
PII w[N], d[N];
signed main() {
    freopen("sequence.in", "r", stdin);
    freopen("sequence.ans", "w", stdout);
    cin >> n >> T;
    for (int i = 1; i <= n; i++) scanf("%d", &w[i].x), w[i].y = i;
    for (int i = 1; i <= n; i++) scanf("%d", &d[i].x), d[i].y = i;
    sort(w + 1, w + n + 1), sort(d + 1, d + n + 1);
    for (int i = 1; i <= n; i++) rk[w[i].y] = i;
    // 位置在 w[i].y 上的排名第 i
    LL res = 0, cnt = 0;
    for (int i = 1; i <= n; i++) {
        int t = d[i].y;  // 第 i 小的数要到位置 t
        if (w[i].y != t) {
            int r = rk[t];  // 位置 t 上的是哪个
            swap(rk[t], rk[w[i].y]);
            swap(w[i].y, w[r].y);
            cnt++;
        }
        (res += 1ll*(d[i].x - w[i].x)*(d[i].x - w[i].x)) %= P;
    }
    cout << res;
    if (T)
        cout << " " << cnt << endl;
    return 0;
}

D

枚举方阵的大小为 k ,每行给定一个权值 xi ,每列给定一个权值 yi ,那么 ai,j=xi+yj 是一个合法的方阵。

一个合法的方阵也一定可以由一组 xi,yi 表示。 (xi=ai,1,yj=a1,ja1,1)
但是 xi=xi+1,yi=yi1xi,yi 对应的方阵相同。
min(xi)=0 则方阵与数列之间——对应。
此时 ai,jm 等价于 min(yi)m
yi 减去 m ,问题变为将至多 nkm 个石头放入 2k 个格子里,且前 k 个格子至少有一个没有石子的方案数。

容斥求得答案为 (nkm+2k2k)(nkm+k2k)
最后对所有可能的 k 求和。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, mod = 998244353;
int n, m, fac[N], inv[N];
int fpow_(int a, int b, int res = 1){
    for (; b; b >>= 1, a = 1ll * a * a % mod)
        if (b & 1)
            res = 1ll * res * a % mod;
    return res;
}
void init_(int n){
    fac[0] = 1;
    for (int i = 1; i <= n; i++)
        fac[i] = 1ll * fac[i - 1] * i % mod;
    inv[n] = fpow_(fac[n], mod - 2);
    for (int i = n; i; i--)
        inv[i - 1] = 1ll * inv[i] * i % mod;
}
int C_(int n, int k) { return n < k ? 0 : 1ll * fac[n] * inv[k] % mod * inv[n - k] % mod; }
void work_(){
    int ans = 0;
    for (int i = 1; 1ll * i * m <= n; i++){    
        int tot = n - i * m;
        ans = (ans + C_(tot + 2 * i, 2 * i)) % mod;
        ans = (ans - C_(tot + i, 2 * i)) % mod;
    }
    printf("%d\n", (ans % mod + mod) % mod);
}
int main(){
    freopen("magic.in","r",stdin);
    freopen("magic.ans","w",stdout);
    init_(2e5);
    int T;
    scanf("%d", &T);
    while (T--){
        scanf("%d%d", &n, &m);
        work_();
    }
    return 0;
}
posted @   Star_F  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示