codeforces 852F Product transformation(数学)

F. Product transformation
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Consider an array A with N elements, all being the same integer a.

Define the product transformation as a simultaneous update Ai = Ai·Ai + 1, that is multiplying each element to the element right to it for , with the last number AN remaining the same. For example, if we start with an array A with a = 2 and N = 4, then after one product transformation A = [4,  4,  4,  2], and after two product transformations A = [16,  16,  8,  2].

Your simple task is to calculate the array A after M product transformations. Since the numbers can get quite big you should output them modulo Q.

Input

The first and only line of input contains four integers NMaQ (7 ≤ Q ≤ 109 + 1232 ≤ a ≤ 106 + 123 is prime), where  is the multiplicative order of the integer a modulo Q, see notes for definition.

Output

You should output the array A from left to right.

Example
input
2 2 2 7
output
1 2 
Note

The multiplicative order of a number a modulo Q , is the smallest natural number x such that ax mod Q = 1. For example, .


题意:有一个长度为N的数组,每个数字都是a,每一轮从右往左的做A[i]=A[i]*A[i+1]的操作,问第M次轮后每个数字是多少,对Q取余,N,M不超过x(a的x次取余Q为1的最小的x)

题解:只需要求最后每个位置是a的几次就好了,打个表可以发现差值是一个杨辉三角,所以先求出那个x,然后求出所以的C(m,i)对x的余数,从右往左的加起来,如果超过了M+1个就等于右边那个,由于a只有1e6+123,所以x一定小于1e6+123,可以暴力求,不暴力也不行,因为不能求逆元,无奈
代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 1000000+130
using namespace std;
typedef long long ll;
int n, m, a, Q, X;
ll fac[N], inv[N], c[N];
void factorial()
{
    int top = 1e6 + 123;
    fac[0] = 1; for(int i = 1; i <= top; i ++) fac[i] = fac[i - 1] * i % X;
    inv[0] = inv[1] = 1; for(int i = 2; i <= top; i ++) inv[i] = inv[X % i] * (X - X / i) % X;
    for(int i = 2; i <= top; i ++) inv[i] = inv[i] * inv[i - 1] % X;
}
ll C(int n, int m)
{
    return fac[n] * inv[m] % X * inv[n - m] % X;
}
ll quick(ll a,ll b,ll M)
{
    ll c=1;
    while(b)
    {
        if(b&1)c=c*a%M;
        a=a*a%M;
        b>>=1;
    }
    return c;
}
ll ans[N];
int main ()
{
    scanf("%d%d%d%d",&n,&m,&a,&Q);
    X=1;
    while(quick(a,X,Q)!=1)X++;
    factorial();
    for(int i=1;i<=m+1;i++){
        c[i]=C(m,i-1);
        c[i]=(c[i]+c[i-1])%X;
    }
    for(int i=n;i;i--){
        if(n-i+1<=m+1)ans[i]=c[n-i+1];
        else ans[i]=ans[i+1];
    }
    for(int i=1;i<n;i++)
        printf("%lld ",quick(a,ans[i],Q));
    printf("%lld\n",quick(a,ans[n],Q));
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值