FFT


HDU 1402 http://acm.hdu.edu.cn/showproblem.php?pid=1402


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=150020;
const double PI=acos(-1.0);
struct Com{//复数,重载+,-,* complex
    double a,b;
    Com(double aa=0,double bb=0){a=aa;b=bb;}
    Com operator +(const Com &e){return Com(a+e.a,b+e.b);}
    Com operator -(const Com &e){return Com(a-e.a,b-e.b);}
    Com operator *(const Com &e){return Com(a*e.a-b*e.b,a*e.b+b*e.a);}
};
void change(Com y[],int len){
    int i,j,k;
    for(i=1,j=len/2;i<len-1;i++){
        if(i<j) swap(y[i],y[j]);
        k=len/2;
        while(j>=k){
            j-=k;
            k/=2;
        }
        if(j<k)j+=k;
    }
}
//FFT快速傅里叶变换的模板,用以将多项式系数转换成单位根(??应该是),这样得到的两个序列逐个相乘到得就是系数
//序列的卷积,即两个多项式乘积后的系数值
void FFT(Com y[],int len,int on){
    change(y,len);
    for(int h=2;h<=len;h<<=1){
        Com wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(int j=0;j<len;j+=h){
            Com w(1,0);
            for(int k=j;k<j+h/2;k++){
                Com u=y[k];
                Com t=w*y[k+h/2];
                y[k]=u+t;
                y[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if(on==-1)
        for(int i=0;i<len;i++)
            y[i].a/=len;
}
int n;
char s1[maxn/3];
char s2[maxn/3];
int l1,l2,l;
int ans[maxn];
Com x1[maxn],x2[maxn];

int main(){
    while(scanf("%s%s",s1,s2)!=EOF){
        l1=strlen(s1);
        l2=strlen(s2);
        l=1;
        while(l<=l1+l2) l<<=1;  // 必须 l>l1+l2 && l>2^.. !!!
        for(int i=l1-1;i>=0;i--) x1[l1-i-1]=Com(s1[i]-'0',0);
        for(int i=l1;i<l;i++) x1[i]=Com(0,0);
        
        for(int i=l2-1;i>=0;i--) x2[l2-i-1]=Com(s2[i]-'0',0);
        for(int i=l2;i<l;i++) x2[i]=Com(0,0);
        
        FFT(x1,l,1);FFT(x2,l,1);
        for(int i=0;i<l;i++)
            x1[i]=x1[i]*x2[i];
        FFT(x1,l,-1);
        
        //memset(ans,0,sizeof(ans));
        for(int i=0;i<l;i++){
            if(i==0) ans[i]=(x1[i].a+0.5);
            else{
                ans[i]=ans[i-1]/10+(x1[i].a+0.5);
                ans[i-1]%=10;
            }
        }
        int k=l-1;
        while(ans[k]==0&&k>0) k--;
        for(int i=k;i>=0;i--) printf("%d",ans[i]);
        puts("");
    }
}


/*
A*B
Sample Input
1
2

1000 
2
 
Sample Output
2
2000
*/


HDU 4609  http://acm.hdu.edu.cn/showproblem.php?pid=4609


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=300020;
const double PI=acos(-1.0);
struct Com{//复数,重载+,-,* complex
    double a,b;
    Com(double aa=0,double bb=0){a=aa;b=bb;}
    Com operator +(const Com &e){return Com(a+e.a,b+e.b);}
    Com operator -(const Com &e){return Com(a-e.a,b-e.b);}
    Com operator *(const Com &e){return Com(a*e.a-b*e.b,a*e.b+b*e.a);}
};
void change(Com y[],int len){
    int i,j,k;
    for(i=1,j=len/2;i<len-1;i++){
        if(i<j) swap(y[i],y[j]);
        k=len/2;
        while(j>=k){
            j-=k;
            k/=2;
        }
        if(j<k)j+=k;
    }
}
//FFT快速傅里叶变换的模板,用以将多项式系数转换成单位根(??应该是),这样得到的两个序列逐个相乘到得就是系数
//序列的卷积,即两个多项式乘积后的系数值
void FFT(Com y[],int len,int on){
    change(y,len);
    for(int h=2;h<=len;h<<=1){
        Com wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(int j=0;j<len;j+=h){
            Com w(1,0);
            for(int k=j;k<j+h/2;k++){
                Com u=y[k];
                Com t=w*y[k+h/2];
                y[k]=u+t;
                y[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if(on==-1)
        for(int i=0;i<len;i++)
            y[i].a/=len;
}
int cnt[maxn];
int num[maxn];
Com x1[maxn];
Com x2[maxn];
ll sum[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int l=1,m;
        scanf("%d",&m);
        int n=0;
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<m;i++){scanf("%d",&num[i]);cnt[num[i]]++;n=max(n,num[i]);}
        while(l<=(n+n)) l<<=1;
        for(int i=0;i<l;i++) x1[i]=x2[i]=Com(cnt[i],0);
        FFT(x1,l,1);FFT(x2,l,1);
        for(int i=0;i<l;i++) x1[i]=x1[i]*x2[i];
        FFT(x1,l,-1);
        for(int i=0;i<l;i++) sum[i]=(ll)(x1[i].a+0.5);
        for(int i=0;i<m;i++) sum[num[i]+num[i]]--;
        for(int i=0;i<l;i++) sum[i]/=2;
        for(int i=1;i<l;i++) sum[i]+=sum[i-1];
        ll all=(ll)m*((ll)m-1)*((ll)m-2)/6;
        ll ans=all;
        for(int i=0;i<m;i++) ans-=sum[num[i]];
        printf("%.7f\n",(double)(ans)/all);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值