zoukankan      html  css  js  c++  java
  • P3599 Koishi Loves Construction——构造题

    题目

    Task1:试判断能否构造并构造一个长度 $n$ 的 $1...n$ 的排列,满足其 $n$ 个前缀和在模 $n$ 的意义下互不相同

    Task2:试判断能否构造并构造一个长度 $n$ 的 $1...n$ 的排列,满足其 $n$ 个前缀积在模 $n$ 的意义下互不相同。

    分析

    既然考虑原数列很难,就直接考虑前缀和和前缀积。

    对于task1:

    在模 $n$ 意义下,${1,2,3,...n}$ 等价于 $ {0,1,-1,2,-2,... }$,我们将它设为前缀和。

    其次,我们可以发现 $n$ 必定出现在数列的第一位,否则 $n$ 出现前后的两个前缀和会相等。已知首项,已知前缀和,就可以推出各项。奇数不行。

    总结:

    当 $n$ 为奇数时,无法构造出合法解(1特判)

    当 $n$ 为偶数时,可以构成形如 $n, n-1, 2, n-3, 4...$ 这样的数列

    对于Task2:

    根据消元法,构造数列 $1,frac{2}{1},frac{3}{2},...,frac{n-1}{n-2}$。

    显然,合数没有解,因为其两个两个因子相乘之后,后面取模都为0了。

    显然,首项为1,末项为n。

    只需证明中间那些数是互不相同的。因为 $frac{k+1}{k} = 1 + frac{1}{k}$,当 $n$为质数时,每个元素都有逆元且不相同。

    总结:

    当 $n$ 为合数,无法构造出合法解(特判4)

    当 $n$ 为质数,可以构造形如 $1,frac{2}{1},frac{3}{2},...,frac{n-1}{n-2},n$.(特判1)

    注意开 long long!!!

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 100000 + 10;
    int task, T;
    int n;
    
    void solve1()
    {
        if(n ==  1)
        {
            printf("2 1
    ");
            return;
        }
        if(n&1)
        {
            printf("0
    ");
            return;
        }
        printf("2 %d ", n);
        ll pre = 0;
        //printf("n:%d
    ", n);
        for(int i = 1;i < n;i++)
        {
            int tmp = ((i&1) == 0 ? 1 : -1) * ((i+1) / 2); //printf("tmp: %d
    ", tmp);
            printf("%d", (tmp -pre+n)%n);
            if(i == n-1)  printf("
    ");
            else printf(" ");
            pre = tmp;
        }
    }
    
    bool is_prime[maxn + 1];
    void sieve(int n)
    {
        int m = (int)sqrt(n + 0.5);
        memset(is_prime, true, sizeof(is_prime));
        is_prime[0] = is_prime[1] = false;                //1是特例
        for (int i = 2; i <= m; i++)  if (is_prime[i])
            for (int j = i * i; j <= n; j += i)  is_prime[j] = false;
    }
    
    int inv[maxn];
    void init_inv(int n, int mod)
    {
        inv[1] = 1;
        for(int i = 2;i < n;i++)  inv[i] = 1LL * (mod -  mod / i) * inv[mod % i] % mod;  //加mod不改变结果
    }
    
    void solve2()
    {
        if(n == 1)
        {
            printf("2 1
    ");
            return;
        }
        if(n == 4)
        {
            printf("2 1 3 2 4
    ");
            return;
        }
        sieve(n);
        if(!is_prime[n])
        {
            printf("0
    ");
            return;
        }
        init_inv(n, n);
        printf("2 1 ");
        for(int i = 2;i <= n-1;i++)  printf("%d ", 1LL * i * inv[i-1] % n);
        printf("%d
    ", n);
    }
    
    int main()
    {
        scanf("%d%d", &task, &T);
        while(T--)
        {
            scanf("%d", &n);
            if(task == 1)  solve1();
            else solve2();
        }
        return 0;
    }

    参考链接:

    1. https://oi-wiki.org/basic/construction/

    2. https://www.luogu.org/problemnew/solution/P3599

  • 相关阅读:
    Shell是linux下的脚本语言解析器
    semver 是 语义化版本
    js中限制字符串输入中英文字符的长度封装
    chalk.js(node终端样式库)
    分页
    利用Nodejs的os.networkInterfaces()模块修改vuecli项目默认打开地址
    物理像素
    长列表优化eg
    [JSOI2008]球形空间产生器
    标记不下传线段树(混蛋树)
  • 原文地址:https://www.cnblogs.com/lfri/p/11337303.html
Copyright © 2011-2022 走看看