XJTUOJ wmq的A×B Problem FFT

wmq的A×B Problem

发布时间: 2017年4月9日 17:06   最后更新: 2017年4月9日 17:07   时间限制: 3000ms   内存限制: 512M

描述

这是一个非常简单的问题。

wmq如今开始学习乘法了!他为了训练自己的乘法计算能力,写出了n个整数,并且对每两个数a,b都求出了它们的乘积a×b。现在他想知道,在求出的n(n−1)2个乘积中,除以给定的质数m余数为k(0≤k<m)的有多少个。

输入

第一行为测试数据的组数。

对于每组测试数据,第一行为2个正整数n,m,2≤n,m≤60000,分别表示整数的个数以及除数。

接下来一行有n个整数,满足0≤ai≤109。

保证总输出行数∑m≤3×105。

输出

对每组数据输出m行,其中第i行为除以m余数为(i−1)的有多少个。

样例输入1

2
4 5
2 0 1 7
4 2
2 0 1 6

样例输出1

3
0
2
0
1
6
0

题解:

  m是素数,显然,利用原根性质

  i -> g^i

  此时g为m的原根

  首先 模剩余系 为0~m-1,那么模为 i * j 转化为 g^(i+j)

  即FFT求解

  最后转化回来即可

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 333333+10, M = 1e3+20,inf = 2e9,mod = 469762049;

int MOD;
inline int mul(int a, int b){
    return (long long)a * b % MOD;
}
int power(int a, int b){
    int ret = 1;
    for (int t = a; b; b >>= 1){
        if (b & 1)ret = mul(ret, t);
        t = mul(t, t);
    }
    return ret;
}
int cal_root(int mod)
{
    int factor[20], num = 0, s = mod - 1;
    MOD = mod--;
    for (int i = 2; i * i <= s; i++){
        if (s % i == 0){
            factor[num++] = i;
            while (s % i == 0)s /= i;
        }
    }
    if (s != 1)factor[num++] = s;
    for (int i = 2;; i++){
        int j = 0;
        for (; j < num && power(i, mod / factor[j]) != 1; j++);
        if (j == num)return i;
    }
}
struct Complex {
    long double r , i ;
    Complex () {}
    Complex ( double r , double i ) : r ( r ) , i ( i ) {}
    Complex operator + ( const Complex& t ) const {
        return Complex ( r + t.r , i + t.i ) ;
    }
    Complex operator - ( const Complex& t ) const {
        return Complex ( r - t.r , i - t.i ) ;
    }
    Complex operator * ( const Complex& t ) const {
        return Complex ( r * t.r - i * t.i , r * t.i + i * t.r ) ;
    }
} ;

void FFT ( Complex y[] , int n , int rev ) {
    for ( int i = 1 , j , t , k ; i < n ; ++ i ) {
        for ( j = 0 , t = i , k = n >> 1 ; 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 ) {
        Complex wn = Complex ( cos ( rev * 2 * pi / s ) , sin ( rev * 2 * pi / s ) ) , w ( 1 , 0 ) , t ;
        for ( int k = 0 ; k < ds ; ++ k , w = w * wn ) {
            for ( int i = k ; i < n ; i += s ) {
                y[i + ds] = y[i] - ( t = w * y[i + ds] ) ;
                y[i] = y[i] + t ;
            }
        }
    }
    if ( rev == -1 ) for ( int i = 0 ; i < n ; ++ i ) y[i].r /= n ;
}

Complex s[N];
int T,n,m,x,num[N];
LL ans[N],mo[N],fmo[N];
int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        int G = cal_root(m);
        for(LL i = 0, t = 1; i < m-1; ++i,t = t*G%m)
            mo[i] = t,fmo[t] = i;
        memset(num,0,sizeof(num));
        LL cnt0 = 0;
        for(int i = 0; i <= m; ++i) ans[i] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d",&x);
            x%=m;
            if(x == 0) cnt0++;
            else {
                num[fmo[x]]++;
            }
        }
        int n1 = 1;
        for(n1=1;n1<=(2*m-2);n1<<=1);
        for(int i = 0; i < m; ++i) s[i] = Complex(num[i],0);
        for(int i = m; i < n1; ++i) s[i] = Complex(0,0);
        FFT(s,n1,1);
        for(int i = 0; i < n1; ++i) s[i] = s[i]*s[i];
        FFT(s,n1,-1);
        printf("%lld\n",(LL)cnt0*(n-cnt0)+(LL)cnt0*(cnt0-1)/2);
        for(int i = 0; i <= 2*m-2; ++i) {
            LL now = (LL)(s[i].r+0.5);
            if(i%2==0) now -= num[i/2];
            now/=2;
            ans[mo[i%(m-1)]] += now;
        }
        for(int i = 1; i < m; ++i) printf("%lld\n",ans[i]);
    }
    return 0;
}

  

时间: 2024-07-31 14:30:28

XJTUOJ wmq的A×B Problem FFT的相关文章

wmq的A&#215;B Problem

wmq的A×B Problem 题目链接:http://oj.xjtuacm.com/problem/13/ 题目大意:$T$组数据,每组给出$n$个数$a_i$及一个素数$m$,求这$n$个数两两相乘模$m$余$k$有多少个($0\leqslant k < m$). 数论+FFT 原根的概念 设$n \geqslant 1$,$(a,n)=1$,使得$a^d \equiv 1(mod n)$成立的最小的正整数$d$,被称为$a$对模$n$的阶,记做$\delta_n(a)$. 当$\delta

南阳524 A-B Problem

A-B Problem 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 A+B问题早已经被大家所熟知了,是不是很无聊呢?现在大家来做一下A-B吧. 现在有两个实数A和B,聪明的你,能不能判断出A-B的值是否等于0呢? 输入 有多组测试数据.每组数据包括两行,分别代表A和B. 它们的位数小于100,且每个数字前中可能包含+,- 号. 每个数字前面和后面都可能有多余的0. 每组测试数据后有一空行. 输出 对于每组数据,输出一行. 如果A-B=0,输出YES,否则输出NO

NYOJ A-B Problem

A-B Problem 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 A+B问题早已经被大家所熟知了,是不是很无聊呢?现在大家来做一下A-B吧. 现在有两个实数A和B,聪明的你,能不能判断出A-B的值是否等于0呢? 输入 有多组测试数据.每组数据包括两行,分别代表A和B. 它们的位数小于100,且每个数字前中可能包含+,- 号. 每个数字前面和后面都可能有多余的0. 每组测试数据后有一空行. 输出 对于每组数据,输出一行. 如果A-B=0,输出YES,否则输出NO

2016 acm香港网络赛 A题. A+B Problem (FFT)

原题地址:https://open.kattis.com/problems/aplusb FFT代码参考kuangbin的博客:http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html A+B Problem Given N integers in the range [−50000,50000], how many ways are there to pick three integers ai, aj, ak, such

XJTUOJ wmq的队伍(树状数组求 K 元逆序对)

题目链接:http://oj.xjtuacm.com/problem/14/[分析]二元的逆序对应该都会求,可以用树状数组.这个题要求K元,我们可以看成二元的.我们先从后往前求二元逆序对数, 然后对于每一个数就可以求出在这个数后面的比他小的数的数量.然后我们再加一元时,当前扫到a[i],那么在树状数组中,对于那些比他大的数的 逆序对数+=上一元a[i]的逆序对数. #include <bits/stdc++.h> #define met(a,b) memset(a,b,sizeof a) #d

NYOJ:题目524 A-B Problem

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=860 My思路: 先用两个字符串储存这两个实数,然后再用另外两个字符串储存去掉符号和前后多余的0后的新"实数",最后只需要比较两个化简后的新字符就ok了. My代码实现: 1 #include<iostream> 2 using namespace std; 3 string simplify(string s) { //去字符串s的正负号和首尾多余的0 4 str

P2421 A-B数对(增强版)

题目背景 woshiren在洛谷刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:A-B Problem,难倒了一群小朋友,哈哈. 题目描述 给出N 个从小到大排好序的整数,一个差值C,要求在这N个整数中找两个数A 和B,使得A-B=C,问这样的方案有多少种? 例如:N=5,C=2,5 个整数是:2 2 4 8 10.答案是3.具体方案:第3 个数减第1 个数:第3 个数减第2 个数:第5 个数减第4 个数. 输入输出格式 输入格式: 第一行2 个正整数:N,C.

洛谷——P2421 A-B数对(增强版)

题目背景 woshiren在洛谷刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:A-B Problem,难倒了一群小朋友,哈哈. 题目描述 给出N 个从小到大排好序的整数,一个差值C,要求在这N个整数中找两个数A 和B,使得A-B=C,问这样的方案有多少种? 例如:N=5,C=2,5 个整数是:2 2 4 8 10.答案是3.具体方案:第3 个数减第1 个数:第3 个数减第2 个数:第5 个数减第4 个数. 输入输出格式 输入格式: 第一行2 个正整数:N,C.

【南阳OJ分类之大数问题】题目+AC代码汇总

声明:题目部分皆为南阳OJ题目,代码部分包含AC代码(可能不止一个)和标程. 由于大数问题用c/c++写比较麻烦,而Java的大数类又很好用,所以基本为java代码.实际上竞赛很少会考大数问题,因为竞赛是比的算法,而不是语言特性,不过很多都是大数据,数据上千万级别的,所以算法又很关键,显然那和这篇博客也没啥关系. 题目不是太难,大家和本人就权当学习或复习下Java吧O(∩_∩)O~. 该分类南阳oj地址:http://acm.nyist.edu.cn/JudgeOnline/problemset