【ZOJ 3856】Goldbach(FFT)

题意:最多使用三个质数做加法和乘法,问得到X有多少种方案。

这道题的话分几种情况讨论清楚就好了。

1、只有一个数的情况,如果这个数是质数则方案数加1

2、有两个数的情况,可以将两个数做加法和乘法,加法的话将质数得到的数字做一遍FFT,乘法直接做sqrt(n) * sqrt(n)就好了

3、有三个数的情况,分别有三种方法,分别是a + b + c, a + b * c,a * b * c

对于a * b * c,暴力遍历一遍就好,对于a + b * c,首先暴力遍历下b * c,然后再将一个数的两个数的做一遍fft就好,唯一比较麻烦的是a + b + c,这里又可以分为三种情况

(1)三个数都不相同,可以先算出x = a + b的方案数,然后再直接和c做FFT,再将答案除以3就得到方案数

(2)其中三个数相同,那么对于询问n,我们可以得到若n / 3 == 0 && n / 3为质数,则方案数+1

(3)对于只有两个数相同的方案数,那么我们可以先枚举一下。若所求数为9,则两个数相同的方案数有2 + 2 + 5,但是若直接按照(1)中的计数方法进行计算的话,就会出现(2 + 2) + 5,(2 + 5) + 2这两种方案(事实上只算一种),而且对于情况(2),又变得无法区分了。因此我的解决方案是,将x = a + b 中的a == b的情况先去除,这样就保证了计算结果中不会出现(2)即a == b && b == c,然后最后在统计是否满足(2)。并且因为在去除除了a==
b之后,只会出现三个数互不相等和只有一对数相等的情况,则对于询问n,可以求出n = 2 * a + c的个数tt,然后最后的方案数就是(cnt3[n] + tt * 2) / 3。

具体过程可见代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 80005;
const double pi = acos(-1.0);
const int mod = 1e9 + 7;
typedef long long LL;
struct Complex{
    double r,i;
    Complex(double r = 0.0,double i = 0.0):r(r),i(i){}
    Complex operator + (const Complex &a)const{
        return Complex(r + a.r,i + a.i);
    }
    Complex operator - (const Complex &a)const{
        return Complex(r - a.r,i - a.i);
    }
    Complex operator * (const Complex &a)const{
        return Complex(r * a.r - i * a.i,r * a.i + i * a.r);
    }
    Complex operator * (const double &a)const{
        return Complex(r * a,i * a);
    }
};
int tn = ceil(log(8 * 1e4) / log(2.0)) + 1;
int prime[N],pcnt;
bool isprime[N];
LL res[N],cnt3[N];
LL cnt[N],cnt2[N],cnt11[N];
Complex x1[N << 2],x2[N << 2],tmp[N << 2];
int rev(int x){
    int res = 0;
    for(int i = 0 ; i < tn ; i ++){
        if(x & 1) res += 1 << tn - 1 - i;
        x >>= 1;
    }
    return res;
}
void fft(Complex A[],int n,int op){
    for(int i = 0 ; i < n ; i ++) tmp[ rev(i) ] = A[i];
    for(int i = 0 ; i < n ; i ++) A[i] = tmp[i];
    for(int i = 1 ; (1 << i) <= n ; i ++){
        int m = 1 << i;
        Complex wn(cos(op * 2 * pi / m),sin(op * 2 * pi / m));
        for(int k = 0 ; k < n ; k += m){
            Complex w(1,0),u,t;
            for(int j = 0 ; j < m / 2 ; j ++){
                u = A[k + j];
                t = w * A[k + j + m / 2];
                A[k + j] = u + t;
                A[k + j + m / 2] = u - t;
                w = w * wn;
            }
        }
    }
    if(op == -1)
        for(int i = 0 ; i < n ; i ++)
            A[i] = A[i] * (1.0 / n);
}
void getprime(){
    isprime[0] = isprime[1] = 1;
    for(int i = 4 ; i < N ; i += 2) isprime[i] = 1;
    for(int i = 3 ; i < N ; i += 2){
        if(isprime[i] == 0)
            for(int j = i + i ; j < N ; j += i)
                isprime[j] = 1;
    }
    pcnt = 0;
    for(int i = 2 ; i < N ; i ++) if(isprime[i] == 0) prime[pcnt ++] = i;
}
int len = 1 << tn;
void init(){
    for(int i = 0 ; i < pcnt ; i ++) cnt[ prime[i] ] ++;
    for(int i = 0 ; prime[i] * prime[i] < N ; i ++)
    for(int j = i ; j < pcnt && prime[i] * prime[j] < N ; j ++)
        cnt2[ prime[i] * prime[j] ] ++;
}
void do1(){
    for(int i = 0 ; i < pcnt ; i ++) res[ prime[i] ] ++;
}
void do2(){
    for(int i = 0 ; i < N ; i ++) res[i] += cnt2[i];//*
    for(int i = 0 ; i < N ; i ++) x1[i] = Complex(cnt[i],0);
    for(int i = N ; i < len ; i ++) x1[i] = Complex(0,0);
    fft(x1,len,1);
    for(int i = 0 ; i < len ; i ++) x1[i] = x1[i] * x1[i];
    fft(x1,len,-1);
    for(int i = 0 ; i < N ; i ++){
        if(i % 2 == 0 && !isprime[i / 2])
            cnt11[i] = (LL(x1[i].r + 0.5) + 1) / 2;
        else
            cnt11[i] = LL(x1[i].r + 0.5) / 2;
        res[i] = (res[i] + cnt11[i]) % mod;
    }//+
}
void do3(){
    for(int i = 0 ; prime[i] * prime[i] * prime[i] < N ; i ++)
    for(int j = i ; prime[i] * prime[j] * prime[j] < N ; j ++)
    for(int k = j ; k < pcnt && prime[i] * prime[j] * prime[k] < N ; k ++){
        res[ prime[i] * prime[j] * prime[k] ] ++;
    }
    for(int i = 0 ; i < N ; i ++) if(res[i] >= mod) res[i] -= mod;
    //* and *
    for(int i = 0 ; i < N ; i ++) x1[i] = Complex(cnt[i],0);
    for(int i = N ; i < len ; i ++) x1[i] = Complex(0,0);
    for(int i = 0 ; i < N ; i ++) x2[i] = Complex(cnt2[i],0);
    for(int i = N ; i < len ; i ++) x2[i] = Complex(0,0);
    fft(x1,len,1);
    fft(x2,len,1);
    for(int i = 0 ; i < len ; i ++) x1[i] = x1[i] * x2[i];
    fft(x1,len,-1);
    for(int i = 0 ; i < N ; i ++) res[i] = (res[i] + LL(x1[i].r + 0.5)) % mod;
    // + and *
    for(int i = 0 ; i < N ; i ++) x1[i] = Complex(cnt11[i] - (i % 2 == 0 && !isprime[i / 2]),0);
    for(int i = N ; i < len ; i ++) x1[i] = Complex(0,0);
    for(int i = 0 ; i < N ; i ++) x2[i] = Complex(cnt[i],0);
    for(int i = N ; i < len ; i ++) x2[i] = Complex(0,0);
//    for(int i = 0 ; i < 10 ; i ++) printf("%I64d ",i);printf("\n");
//    for(int i = 0 ; i < 10 ; i ++) printf("%.3f ",x1[i].r);printf("\n");
//    for(int i = 0 ; i < 10 ; i ++) printf("%.3f ",x2[i].r);printf("\n");
    fft(x1,len,1);
    fft(x2,len,1);
    for(int i = 0 ; i < len ; i ++) x1[i] = x1[i] * x2[i];
    fft(x1,len,-1);
    for(int i = 0 ; i < N ; i ++) cnt3[i] = LL(x1[i].r + 0.5);
//    for(int i = 0 ; i < 10 ; i ++) printf("%I64d ",cnt3[i]);printf("\n");
    //+ and +
}
int main()
{
    getprime();
    init();
    do1();
    do2();
    do3();
    int n;
    while(~scanf("%d",&n)){
        LL ans = res[n],tt = 0;
        for(int i = 0 ; i < pcnt && 2 * prime[i] <= n ; i ++){
            if(!isprime[ n - 2 * prime[i] ] && n != prime[i] * 3) tt ++;
        }
        if(n % 3 == 0 && !isprime[n / 3]) ans ++;
        ans = (ans + (cnt3[n] + 2 * tt) / 3) % mod;
        printf("%lld\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 17:45:31

【ZOJ 3856】Goldbach(FFT)的相关文章

【Hibernate学习】 ——ORM(三)

前面几种关系我们以前就经常用,对于继承我们也并不陌生,经常接触的类与类之间的继承用extends关键字,那么在表与表的关系中如何表示呢?下面我们来讲继承映射. 继承有三种实现的策略,单表继承,具体表继承,类表继承.下面来分析一下这三种方式 继承关联类关系  单表继承 每棵类继承树使用一个表,可知,这三个类在一张表中.如下表: 这张表包括了父类,子类的所有属性,通过Type来区分是哪个子类. 对象模型映射到关系模型: <classname="com.bjpowernode.hibernat.

【Hibernate学习】 ——ORM(一)

Hibernate是一种能实现ORM的框架.ORM即Object Relational Mapping,对象关系映射.也就是将关系数据库中表的数据映射成为对象,也就是说将表与表之间的操作映射成对象与对象之间的操作,通过实体类来达到操作表的目的.总之就是把对数据库的操作转化为对对象的操作,从而更体现了面向对象的思想. 一对一关联映射策略包括主键关联和唯一外键关联. 单向一对一 主键关联 让两个对象有相同的主键值,表名它们之间的一对一关系,数据库没有额外的字段来维护它们之间的关系,仅仅通过表的主键来

【Hibernate学习】 ——ORM(二)

上篇博客主要介绍了一对一的关系,主要理解单向与双向的区别,主键关联与唯一外键关联的区别.下面继续介绍一对多与多对多关联. 一对多关联映射 一个班级对应多个学生 单向一对多关系 关系表: classes代码 <classname="com.bjpowernode.hibernat.Classes"table="t_classes"> <idname="id"> <generatorclass="native&

【HDOJ 5838】Mountain(局部极小值)

[HDOJ 5838]Mountain(局部极小值) Mountain Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Zhu found a map which is a N * M rectangular grid.Each cell has a height and there are no two cells which have

【POJ 3071】 Football(DP)

[POJ 3071] Football(DP) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4350   Accepted: 2222 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all tea

【POJ 3034】 Whac-a-Mole(DP)

[POJ 3034] Whac-a-Mole(DP) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3621   Accepted: 1070 Description While visiting a traveling fun fair you suddenly have an urge to break the high score in the Whac-a-Mole game. The goal of the W

【UOJ#246】套路(动态规划)

[UOJ#246]套路(动态规划) 题面 UOJ 题解 假如答案的选择的区间长度很小,我们可以做一个暴力\(dp\)计算\(s(l,r)\),即\(s(l,r)=min(s(l+1,r),s(l,r-1),abs(a_r-a_l))\). 我们发现\(s(l,r)\le \frac{m}{r-l+1}\),那么当长度足够大的时候\(s(l,r)\)的取值很小. 所以我们对于询问分治处理,当长度小于\(\sqrt m\)时,直接\(dp\)计算贡献. 否则,当长度大于\(\sqrt m\)时,枚举

【UOJ#22】【UR #1】外星人(动态规划)

[UOJ#22][UR #1]外星人(动态规划) 题面 UOJ 题解 一道简单题? 不难发现只有按照从大往小排序的顺序选择的才有意义,否则先选择一个小数再去模一个大数是没有意义的. 设\(f[i][j]\)表示考虑了前\(i\)个数,模完之后是\(j\)的方案数. 转移的时候枚举这个数是模还是不模,如果不模的话就要把它放到后面某个小数的后面,方案数是\(n-i\). #include<iostream> #include<cstdio> #include<cstdlib>

【初识Spring】对象(Bean)实例化及属性注入(xml方式)

title: [初识Spring]对象(Bean)实例化及属性注入(xml方式) date: 2018-08-29 17:35:15 tags: [Java,Web,Spring] --- ?#初识Spring之Bean实例化及属性注入 1.通过xml配置的方式进行实例化. 配置文件中bean标签的常用属性 通过无参构造(常用) 使用静态工厂进行创建 使用实例工厂进行创建 2.属性注入. 使用有参数构造方法注入属性 使用set方法注入属性(常用) 注入对象类型属性 注入复杂类型属性 xml配置的