codeforces 487C Prefix Product Sequence

[链接] http://codeforces.com/problemset/problem/487/C
[sol]

显然,n需要放到最后一个位置上,不然的话后面若干个乘积%p均都为0,与题意相违背。当n为合数时,n

一定能写成一个素数和合数的乘积(4除外),所以除了4以外的合数都没有合法方案。

当n为素数时,令a[i] = i / i-1 % n=i* inv[i - 1](i - 1的逆元);那么形成的序列就是1,2,3,…n-1,0,并且

a[i]=a[j]当且仅当i=j时成立,证明如下:

                    i * inv[i - 1] = j * inv[j - 1]    

同乘(i - 1) * (j - 1)得:

                     i * (j - 1) = j * (i - 1)
                             i = j;

关于逆元的求法,此题需要预处理n以内的逆元,一般用O(n)通过下面这个公式来搞

                      inv[i] = (p - p / i)*inv[p % i] % p;

证明的话就是先化简,然后同乘i* (p % i)即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
ll inv[N];
bool ok(int x)
{
    for(int i = 2; i <= sqrt(x); i++)
        if (x % i == 0)
          return false;
    return true;
}
int main()
{
    int n;
    scanf("%d", &n);
    if (n == 1)
    {
        printf("YES\n1");
        return 0;
    }
    if (n == 4)
    {
        printf("YES\n1\n3\n2\n4\n");
        return 0;
    }
    if (!ok(n))
    {
        printf("NO\n");
        return 0;
    }
    inv[1] = 1;
    printf("YES\n1\n");
    for(int i = 2; i < n; i++)
    {
        inv[i] = 1LL * (n - n / i) * inv[n % i] % n;
        cout<<i * inv[i - 1] % n<<endl;
    }
    printf("%d\n", n);
    return 0;
}

[后话]

本题本来想通过两个限制条件的全排列来搞,这样的话复杂度不知道能优化到哪个程度,事实证明

(n<20)时勉强可以出界

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

const int N = 100000 + 5;
bool f[N], v[N];
int q[N];
int n;
void dfs (int dep,int ans)
{
    if (dep == n - 1)
    {
        printf("-----------------------------------------\n");
        for(int i = 1; i < n; i++)
            printf("%d\n", q[i]);
        printf("-----------------------------------------\n");
        return;
    }
    for(int i = 1; i < n; i++)
        if(!f[i])
           {
               int t = ans * i % n;
               if (v[t] || t>=n)
                  continue;
               f[i] = true;
               v[t] =true;
               q[dep + 1] = i;
               dfs(dep + 1,t);
               f[i] = false;
               v[t] = false;
               q[dep + 1] = 0;
           }
}
int main()
{
    v[0] = true;
    scanf("%d", &n);
    dfs(0,1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值