[SDOI2015] Sequence Statistics (NTT)

Description

Little C has a set S whose elements are all non-negative integers less than M. He programmed a sequence generator to generate a sequence of length N, and each number in the sequence belongs to the set S. Little C uses this generator to generate many such sequences.
But Little C has a problem that needs your help: Given an integer x, find all the numbers that can be generated and satisfy the product of all the numbers in the sequence, mod M, which has a value equal to x.
Little C believes that the two sequence {Ai} and {Bi} are different, if and only if there is at least one integer i, which satisfies Ai≠Bi. In addition, C thinks that the answer to this question may be very big, so he only needs you to help him find the value of mod 1004535809.

Input
one line, four integers, N, M, x, |S|, where |S| is the number of elements in the set S.
The second line, |S| integers, represents all the elements in the set S.
1<=N<=10^9, 3<=M<=8000, M is a prime number
0<=x<=M-1, input data to ensure that the elements in the set S are not repeated x∈[1,m-1]
set The number in ∈[0,m-1]


One line of Output , an integer, represents the value of mod 1004535809 for the number of types you have calculated.

Sample Input
4 3 1 2
1 2
Sample Output
8

[Sample description]
The different numbers that can be generated to meet the requirements are (1,1,1,1), (1,1,2,2), (1,2,1,2), (1,2, 2,1),
(2,1,1,2), (2,1,2,1), (2,2,1,1), (2,2,2,2)

solution

f [ i ] [ j ] f[i][j] f [ i ] [ j ]:Indicates thatiiis selectedThe product of the number of i % m = j \%m=j%m=j的方案数
f [ i < < 1 ] [ j ] = ∑ ( j 1 × j 2 ) % m = j f [ i ] [ j 1 ] × f [ i ] [ j 2 ] f[i<<1][j]=\sum_{(j_1\times j_2)\%m=j}f[i][j_1]\times f[i][j_2] f[i<<1][j]=(j1×j2)%m=jf[i][j1]×f[i][j2]
Multiplication is beyond knowledge at present,
then the multiplication is transformed into the addition on the exponential, and themmis out of bounds.The original root of m , the
title guaranteesmmm is a prime number, there must be primitive root
f [i <<1] [j] = ∑ (j 1 + j 2)% m = jf [i] [j 1] × f [i] [j 2] f[ i<<1][j]=\sum_{(j_1+j_2)\%m=j}f[i][j_1]\times f[i][j_2]f[i<<1][j]=(j1+j2)%m=jf[i][j1]×f[i][j2]
This looks a lot like something that can be convolved. When it
comes to modulo, useNTT NTTN T T,
but this is slightly different from the normal formula.j 1 + j 2 = j j_1+j_2=jj1+j2=j
[ m − 1 , 2 m − 2 ] [m-1,2m-2] [m1,2 m2 ] This will also contribute to the answer, which ism − 1 m-1m1 modulo

code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long 
#define mod 1004535809
#define maxn 20000
int g, len = 1, inv;
int r[maxn], ans[maxn], f[maxn], fi[maxn];

int qkpow( int x, int y, int MOD ) {
    
    
	int ans = 1;
	while( y ) {
    
    
		if( y & 1 ) ans = ans * x % MOD;
		x = x * x % MOD;
		y >>= 1;
	}
	return ans;
}

void NTT( int *c, int f ) {
    
    
	for( int i = 0;i < len;i ++ )
		if( i < r[i] ) swap( c[i], c[r[i]] );
	for( int i = 1;i < len;i <<= 1 ) {
    
    
		int omega = qkpow( ( f == 1 ) ? 3 : mod / 3 + 1, ( mod - 1 ) / ( i << 1 ), mod );
		for( int j = 0;j < len;j += ( i << 1 ) ) {
    
    
			int w = 1;
			for( int k = 0;k < i;k ++, w = w * omega % mod ) {
    
    
				int x = c[j + k], y = w * c[j + k + i] % mod;
				c[j + k] = ( x + y ) % mod;
				c[j + k + i] = ( x - y + mod ) % mod;
			}
		}
	}
	if( f == -1 ) {
    
    
		for( int i = 0;i < len;i ++ )
			c[i] = c[i] * inv % mod;
	}
}

void root( int m ) {
    
    
	int phi = m - 1;
	for( int i = 2;i < m;i ++ ) {
    
    
		bool flag = 1;
		int x = phi;
		for( int j = 2;j * j <= x;j ++ ) {
    
    
			if( phi % j ) continue;
			while( x % j == 0 ) x /= j;
			if( qkpow( i, phi / j, m ) == 1 ) {
    
    
				flag = 0;
				break;
			}
		}
		if( x > 1 && qkpow( i, phi / x, m ) == 1 ) continue;
		if( flag ) {
    
    
			g = i;
			return;
		} 
	}
}

signed main() {
    
    
	int n, m, x, s;
	scanf( "%lld %lld %lld %lld", &n, &m, &x, &s );
	root( m );
	for( int i = 0;i < m - 1;i ++ ) fi[qkpow( g, i, m )] = i;
//g^i=_(mod m) 相乘转化为指数相加 指数相加就可以用NTT暴艹卷积  
	for( int i = 1, a;i <= s;i ++ ) {
    
    
		scanf( "%lld", &a );
		if( ! a ) continue;
		else f[fi[a]] ++;
	}
	int l = 0;
	while( len <= ( ( m - 1 ) << 1 ) ) {
    
    
		len <<= 1;
		l ++;
	}
	inv = qkpow( len, mod - 2, mod );
	for( int i = 0;i < len;i ++ )
		r[i] = ( r[i >> 1] >> 1 ) | ( ( i & 1 ) << ( l - 1 ) );
	ans[0] = 1;
	while( n ) {
    
    
		if( n & 1 ) {
    
    
			NTT( f, 1 );
			NTT( ans, 1 );
			for( int i = 0;i < len;i ++ ) ans[i] = ans[i] * f[i] % mod;
			NTT( f, -1 );
			NTT( ans, -1 );
			for( int i = m - 1;i < len;i ++ )
//a^b=_(%p)<=>a^[b%phi(p)]=_(%p) 指数以m-1为一个循环节 在%m后应该都是一样的 对最后%m=x的答案可能会有贡献 
				ans[i % ( m - 1 )] = ( ans[i % ( m - 1 )] + ans[i] ) % mod, ans[i] = 0;
		}
		NTT( f, 1 );
		for( int i = 0;i < len;i ++ ) f[i] = f[i] * f[i] % mod;
		NTT( f, -1 );
		for( int i = m - 1;i < len;i ++ ) 
			f[i % ( m - 1 )] = ( f[i % ( m - 1 )] + f[i] ) % mod, f[i] = 0;
		n >>= 1;
	}
	printf( "%lld\n", ans[fi[x]] );
	return 0;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113682765