• CF G. Running Competition (NTT, 思维)


    题目:传送门

    题意

    在直角坐标系中,有 n + 1 条线段,第一条线段连接着 (0, 0) , (0, y),最后一条线段连接着 (x, 0) , (x,y),第 i 条线段,连接着 (ai, 0) , (ai, y), 0 = a0 < a1 < a2 < .... < an = n。你能从任何点开始绕着线段走,并最终回到出发点,且你不能走已经走过的点,你走过的线段的总长度就是你此次行动得到的 len.

     如图,红色方框的长度即为此次行动得到的 len, 即 len = 24。

    现在有 q 次询问,每次询问输入一个数 Li, 问你是否存在一种行动,使得行动得到的 len,满足 Li % len == 0,若存在输出最大的 len,不存在输出 -1.

     思路

    观察发现,每次行动必定是一个矩形,且其中两条边的长度等于 y,另外两条边的长度等于 ai - aj (0 <= j < i <= n).

    我们令 b[i] = x - a[i],构造两个多项式 A, B,A[i] 的第 a[i] 项的系数为 1,B[i] 的第 b[i] 项的系数为 1.

    令多项式 C = A * B,多项式相乘可以用 NTT 做,复杂度 o(n*logn)

    若 C[k] 的系数不为 0,则表示存在数组 a 的一个数 a[i] 和 数组 b 的一个数  b[j]  相加等于 k.

    又 a[i] + b[j] = a[i] - a[j] + x,那我们可以通过判断 C[ tmp + x ] 是否不为 0,从而来判断是否存在数组 a 的两个数, a[i],a[j],使得 a[i] - a[j] = tmp

    由于 a[i] - a[j] 的取值范围为 [1, x], 所以我们只需要枚举 k = [1,x] 判断 C[ k + x ] 是否等于 0,若不等于 0,则用 2 * (k + y) 去更新答案数组,复杂度 o(nlogn)

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf 0x3f3f3f3f3f3f3f3f
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    
    const LL G = 3;
    const LL mod = 998244353;
    int len, r[N];
    LL g[N], f[N], w[N], x[N], y[N];
    LL power(LL x,LL y) {
        LL ans = 1;
        while(y) {
            if( y & 1 ) ans = ans * x % mod;
            x = x * x % mod;
            y >>= 1;
        }
        return ans;
    }
    void ntt(LL *a, LL f) {
        for (LL i = 0; i < len; i++) {
            if (i < r[i]) swap(a[i], a[r[i]]);
        }
        w[0] = 1;
        for (LL i = 2; i <= len; i *= 2) {
            LL wn;
            if (f == 1) wn = power(G, (LL)(mod - 1) / i);
            else wn = power(G, (LL)(mod - 1) - (mod - 1) / i);
            for (LL j = i / 2; j >= 0; j -= 2) w[j] = w[j / 2];
            for (LL j = 1; j < i / 2; j += 2) w[j] = (w[j - 1] * wn) % mod;
            for (LL j = 0; j < len; j += i) {
                for (LL k = 0 ; k < i / 2; k++) {
                    LL u = a[j + k], v = (a[j + k + i / 2] * w[k]) % mod;
                    a[j + k] = (u + v) % mod;
                    a[j + k + i / 2] = (u - v + mod) % mod;
                }
            }
        }
        if (f == -1) {
            LL inv = power(len, mod - 2);
            for (LL i = 0; i < len; i++) a[i] = (a[i] * inv) % mod;
        }
    }
    void NTT(LL *a, LL *b, LL *c, LL n, LL m) {
        len = 1;
        while (len <= (n + m)) len *= 2;
        LL k = trunc(log(len + 0.5) / log(2));
        for (LL i = 0; i < len; i++) {
            r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
        }
        for (LL i = 0; i < len; i++) {
            if (i < n) x[i] = a[i]; else x[i] = 0;
            if (i < m) y[i] = b[i]; else y[i] = 0;
        }
        ntt(x, 1); ntt(y, 1);
        for (LL i = 0; i < len; i++) c[i] = x[i] * y[i] % mod;
        ntt(c, -1);
    }
    
    LL n, X, Y, a[N];
    
    LL A[N], B[N], ans[N];
    
    void solve() {
    
        mem(ans, -1);
    
        scanf("%lld %lld %lld", &n, &X, &Y);
    
        rep(i, 0, n) {
    
            scanf("%lld", &a[i]);
    
            A[a[i]] = 1;
    
            B[X - a[i]] = 1;
    
        }
    
        NTT(A, B, A, X + 1, X + 1);
    
        rep(i, 1, X) {
    
            if(A[X + i]) {
    
                for(int j = 2 * (i + Y); j < N; j += 2 * (i + Y)) {
    
                    ans[j] = 2 * (i + Y);
    
                }
    
            }
    
        }
    
        int q; scanf("%d", &q);
    
        while(q--) {
    
            int p; scanf("%d", &p);
    
            printf("%lld
    ", ans[p]);
    
        }
    
    }
    
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
  • 相关阅读:
    C# 定时任务
    Web电子签集成开发笔记
    海康威视二次开发笔记
    SQL Server 2008R2创建自动备份计划
    图片上传及显示(包含多文件)
    程序员的孤独
    Iframe用法
    Bootstrap模态框(MVC)
    工作时发现的问题【组织管理】【客户对接】【项目流程】
    为啥有人觉得你写程序写得好,有人觉得你不称职
  • 原文地址:https://www.cnblogs.com/Willems/p/13607837.html
Copyright © 2020-2023  润新知