其他分享
首页 > 其他分享> > [NOIP2016 普及组] 魔法阵

[NOIP2016 普及组] 魔法阵

作者:互联网

洛谷题面

题目大意

给定 \(n,m\) 和 \(m\) 个整数 \(x_i\),\(1\le x_i\le n\)。

如果存在四元组 \((a,b,c,d)\) 满足:

那么这个四元组是有效的,问每个物品分别作为有效四元组中 \(a,b,c,d\) 几次。

题目分析

根据题意可知需要满足三个条件:

令 \(t=x_d-x_c\),所以:

代入 \((2)\) 可得:\(x_b-x_a=2t\)\(~(4)\)

将 \((4)\) 代入 \((3)\) 可得:\(2t\lt (x_c-x_b)/3=6t\lt x_c-x_b\)\(~(5)\)

改一下 \((5)\):\(6t+k=x_c-x_b(k\gt 0)\) \(~(6)\)

根据 \((6)\) 画图可得:(直接用的 这篇题解 的图)

1113423-20180801210708340-1039644464.png

可以看出 \(A\) 的最小值为 \(1\),\(D\) 的最大值为 \(n\)。因此我们尝试枚举 \(t\),因为 \(AD=9t+k\),所以 \(t\) 的范围是 \(t\le (n-1)/9=9t\lt n\)。

然后枚举易掌控的右界即 \(D\),可以表示出 \(C=D-t\),\(A,B\) 的最大值为 \(D-9t-1\) 和 \(D-7t-1\)。

但 \(A,B\) 变小就不好直接控制了,观察到只要 \(x_c-x_b\gt 6t\),那么这个魔法阵一定存在,故当 \(a_1\lt a_2,b_1\lt b_2\) 时,若 \(a_2,b_2\) 与 \(C,D\) 组成魔法阵,那么 \(a_1,b_1\) 与 \(C,D\) 也可以组成魔法阵。所以可以使用前缀和优化。

同理枚举 \(A\),使用后缀和优化就好了。

代码

//2022/3/18
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <climits>//need "INT_MAX","INT_MIN"
#include <cstring>//need "memset"
#include <numeric>
#include <algorithm>
#define enter putchar(10)
#define debug(c,que) cerr << #c << " = " << c << que
#define cek(c) puts(c)
#define blow(arr,st,ed,w) for(register int i = (st);i <= (ed); ++ i) cout << arr[i] << w;
#define speed_up() cin.tie(0),cout.tie(0)
#define mst(a,k) memset(a,k,sizeof(a))
#define Abs(x) ((x) > 0 ? (x) : -(x))
const int mod = 1e9 + 7;
inline int MOD(int x) {
    if(x < 0) x += mod;
    return x % mod;
}
namespace Newstd {
    char buf[1 << 21],*p1 = buf,*p2 = buf;
    inline int getc() {
        return p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1 << 21,stdin),p1 == p2) ? EOF : *p1 ++;
    }
    inline int read() {
        int ret = 0,f = 0;char ch = getc();
        while (!isdigit(ch)) {
            if(ch == '-') f = 1;
            ch = getc();
        }
        while (isdigit(ch)) {
            ret = (ret << 3) + (ret << 1) + ch - 48;
            ch = getc();
        }
        return f ? -ret : ret;
    }
    inline void write(int x) {
        if(x < 0) {
            putchar('-');
            x = -x;
        }
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace Newstd;
using namespace std;

const int ma1 = 1.5e4 + 5,ma2 = 4e4 + 5;
int tong[ma1],a[ma2],matrix[ma2][5];
int n,m;
int main(void) {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    n = read(),m = read();
    for (register int i = 1;i <= m; ++ i) {
        a[i] = read();
        tong[a[i]] ++;
    }
    for (register int t = 1,sum;t * 9 < n; ++ t) {
        sum = 0;
        for (register int A = n - 9 * t - 1;A >= 1; -- A) {
            int B = A + 2 * t;
            int C = A + 8 * t + 1;
            int D = A + 9 * t + 1;
            sum += tong[C] * tong[D];
            matrix[A][1] += sum * tong[B],matrix[B][2] += sum * tong[A];
        }
        sum = 0;
        for (register int D = 9 * t + 2;D <= n; ++ D) {
            int A = D - 9 * t - 1;
            int B = A + 2 * t;
            int C = D - t;
            sum += tong[A] * tong[B];
            matrix[C][3] += sum * tong[D],matrix[D][4] += sum * tong[C];
        }
    }
    for (register int i = 1;i <= m; ++ i) {
        for (register int j = 1;j <= 4; ++ j) {
            printf("%d ",matrix[a[i]][j]);
        }
        enter;
    }

    return 0;
}

标签:NOIP2016,普及,tong,int,sum,魔法阵,lt,include
来源: https://www.cnblogs.com/Coros-Trusds/p/16028915.html