2016北京网络赛 NTT板子(附上素数表)

来源:互联网 发布:大卫罗宾逊数据 编辑:程序博客网 时间:2024/05/29 02:57
#include<bits/stdc++.h>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;typedef long long LL ;const int MAXN = 300010 ;const LL mod = 1945555039024054273 ;//取大一点没事const LL g = 5 ;int nn;LL x1[MAXN] , x2[MAXN] ;LL mul ( LL x , LL y ) {    return ( x * y - ( long long ) ( x / ( long double ) mod * y + 1e-3 ) * mod + mod ) % mod ;}LL power ( LL a , LL b ) {    LL res = 1 , tmp = a ;    while ( b ) {        if ( b & 1 ) res = mul ( res , tmp ) ;        tmp = mul ( tmp , tmp ) ;        b >>= 1 ;    }    return res ;}void DFT ( LL y[] , int n , bool rev ) {    for ( int i = 1 , j , t , k ; i < n ; ++ i ) {        for ( k = n >> 1 , t = i , j = 0 ; k ; k >>= 1 , t >>= 1 ) {            j = j << 1 | t & 1 ;        }        if ( i < j ) swap ( y[i] , y[j] ) ;    }    for ( int s = 2 , ds = 1 ; s <= n ; ds = s , s <<= 1 ) {        LL wn = power ( g , ( mod - 1 ) / s ) ;        if ( !rev ) wn = power ( wn , mod - 2 ) ;        for ( int k = 0 ; k < n ; k += s ) {            LL w = 1 , t ;            for ( int i = k ; i < k + ds ; ++ i , w = mul ( w , wn ) ) {                y[i + ds] = ( y[i] - ( t = mul ( y[i + ds] , w ) ) + mod ) % mod ;                y[i] = ( y[i] + t ) % mod ;            }        }    }}void NTT ( LL x1[] , LL x2[] , int n ) {    DFT ( x1 , n , 1 ) ;    DFT ( x2 , n , 1 ) ;    for ( int i = 0 ; i < n ; ++ i ) x1[i] = mul ( x1[i] , x2[i] ) ;    DFT ( x1 , n , 0 ) ;    LL vn = power ( n , mod - 2 ) ;    for ( int i = 0 ; i < n ; ++ i ) x1[i] = mul ( x1[i] , vn ) ;}void solve () {    int i,n,len=1;LL ans=0;    scanf("%d", &n);nn=n;    memset(x1,0,sizeof(x1));    memset(x2,0,sizeof(x2));    for (i=n-1;i>=0;i--) scanf("%lld", &x1[i]),ans+=x1[i]*x1[i];//因为求循环卷积,所以有个序列要倒过来    for (i=0;i<n;i++) scanf("%lld", &x2[i]),ans+=x2[i]*x2[i];    while (len<2*n) len<<=1;//len必须是2的幂    NTT(x1,x2,len);    LL ret=0;    for(int i=0;i<2*n-1;i++){        ret=max(ret,x1[i]+x1[i+n]);//这里可以自己写个2个4项式相乘的例子,发现x1[i]+x1[i+n]就是那个循环乘积和    }    printf("%lld\n", ans-2*ret);}int main(){    int T;    scanf("%d", &T);    while (T--) solve();    return 0;}//常用费马素数和原根的表/*是这样的,这几天在写 FFT,由于是在模意义下的,需要各种素数……然后就打了个表方便以后查了、如果 r*2^k+1 是个素数,那么在mod r*2^k+1意义下,可以处理 2^k 以内规模的数据,2281701377=17*2^27+1  是一个挺好的数,平方刚好不会爆 long long1004535809=479*2^21+1 加起来刚好不会爆 int 也不错下面是刚刚打出来的表格(gg 是mod(r*2^k+1)的原根)素数  rr  kk  gg3   1   1   25   1   2   217  1   4   397  3   5   5193 3   6   5257 1   8   37681    15  9   1712289   3   12  1140961   5   13  365537   1   16  3786433  3   18  105767169 11  19  37340033 7   20  323068673    11  21  3104857601   25  22  3167772161   5   25  3469762049   7   26  31004535809  479 21  32013265921  15  27  312281701377  17  27  33221225473  3   30  575161927681 35  31  377309411329 9   33  7206158430209    3   36  222061584302081   15  37  72748779069441   5   39  36597069766657   3   41  539582418599937  9   42  579164837199873  9   43  5263882790666241 15  44  71231453023109121    35  45  31337006139375617    19  46  33799912185593857    27  47  54222124650659841    15  48  197881299347898369    7   50  631525197391593473   7   52  3180143985094819841  5   55  61945555039024054273 27  56  54179340454199820289 29  57  3*/
0 0