codeforces 487C C. Prefix Product Sequence(数论+构造)

题目链接:

codeforces 487C


题目大意:

要求找出一个1~n排列的排列,通过
bi=(ij=1ai)%n 构成一个新的0~n-1的排列。


题目分析:

  • 首先我们必须让n位于最后,否则会过早的导致前缀积能够整除n,导致一定不能得到合法的排列,因为合数一定可以分解为p*q,所以会导致pq|(n-1)!,4和1是特例需要特判。
  • 然后我们考虑 (i+1)inv[i] ,因为$(i+1) \cdot inv[i] == (j+1) \cdot inv[j] , 当且仅当i == j ¥
  • 证明如下:
    (i+1)inv[i]=(j+1)inv[j]ij(i+1)inv[i]=ij(j+1)inv[j]j(i+1)=i(j+1)ij+j=ij+ii=j
  • 那么我们知道利用(i+1)*inv[i]能够构成一个排列。
  • 那么这个排列的前缀积就是展开如下:
    a1a2ai=1inv[1]2inv[i2](i1)inv[i1]i=i()

    所以得到的依旧是一个排列符合题目要求的性质。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007

using namespace std;

typedef long long LL;

LL inv[MAX];
int n;

int main ( )
{
    while ( ~scanf ( "%d" , &n ) )
    {
        if ( n == 1 )
        {
            puts ( "YES");
            puts ( "1" );
        }
        else if ( n == 4 )
        {
            puts ( "YES" );
            puts ( "1\n3\n2\n4" );
        }
        else 
        {
            bool flag = true;
            for ( int i = 2 ; i*i <= n ; i++ )
                if ( n%i == 0 ) flag = false;
            if ( flag ) 
            {
                puts ( "YES" );
                puts ( "1" );
                inv[1] = 1;
                for ( int i = 2 ; i < n ; i++ )
                {
                    inv[i] = (LL)(n-n/i)*inv[n%i]%n;
                    printf ( "%I64d\n" , (LL)(i)*inv[i-1]%n );
                }
                printf ( "%d\n" , n );
            }
            else puts ( "NO" );
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值