CodeChef Arithmetic Progressions

https://www.codechef.com/status/COUNTARI

题意:

给出n个数,求满足i<j<k且a[j]-a[i]==a[j]-a[k] 的三元组(i,j,k)的个数

n^2 做法:

枚举j和k,当j右移时,令sum[num[右移之前j的值]]++

每次统计sum[num[j]*2-num[k]]即可

如果没有i<j<k,直接上FFT

但是有了这个限制,可以枚举j,再FFT,复杂度为n*n*log(30000)

考虑一次FFT只算1个j有点儿浪费

能不能算好几个j?

分块!

设每一块的大小为S

答案分三种:

一、3个数都在一个块

用平方复杂度的做法,枚举同一块内的j和k,总时间复杂度为O(n/S*S*S)=O(n*S)

二、2个数在两个块

如果在同一块的数是j和k,从第一块开始枚举j和k,记录前面块的sum,累加sum[num[j]*2-num[k]]

如果在同一块的数是i和j,从最后一块开始枚举i和j,记录后面块的sum,累加sum[num[j]*2-num[i]]

总时间复杂度为O(n/S*S*S)=O(n*S)

三、3个数在三个块

枚举中间的的那一块,sumL记录这个块左边所有数,sumR记录这个块右边所有数

用FFT对sumL和sumR做一次卷积,得到sum

枚举中间那一块的每个数j,累加sum[num[j]*2]

FFT的一个小细节:

不能出现次数为0的项,所以所有数向左移一位,所以最后得到的sum向左移了两位,实际累加sum[num[j]*2-2]

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001
#define M 30001
#define S 500

const int K=(1<<16)+2;

typedef long long LL;

const double pi=acos(-1);

int n,mx,a[N];

int l[M],r[M];

int len=1,rev[K];

struct Complex
{
    double x,y;
    Complex(double x_=0,double y_=0):x(x_),y(y_){}
    Complex operator + (Complex P)
    {
        return Complex(x+P.x,y+P.y);
    }
    Complex operator - (Complex P)
    {
        return Complex(x-P.x,y-P.y);
    }
    Complex operator * (Complex P)
    {
        return Complex(x*P.x-y*P.y,x*P.y+y*P.x);
    }
};
typedef Complex E;

E A[K],B[K]; 

LL ans;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}

void fft(E *a,int ty)
{
    for(int i=0;i<len;++i)
        if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int i=1;i<len;i<<=1)
    {
        E wn(cos(pi/i),ty*sin(pi/i));
        for(int p=i<<1,j=0;j<len;j+=p)
        {
            E w(1,0);
            for(int k=0;k<i;++k,w=w*wn)
            {
                E x=a[j+k],y=a[j+k+i]*w;
                a[j+k]=x+y; a[j+k+i]=x-y;
            }
        }
    }
    if(ty==-1)
    {
        for(int i=0;i<len;++i) a[i].x=a[i].x/len+0.5;
    }
}

void three()
{
    int num=mx*2-2,bit=0;
    while(len<=num) len<<=1,bit++;
    for(int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
    for(int i=1;i<=n;++i) r[a[i]]++;
    int ed;
    for(int t=1;t<=n;t+=S)
    {
        ed=min(n,t+S-1);
        for(int i=t;i<=ed;++i) r[a[i]]--;
        for(int i=0;i<mx;++i) A[i].x=l[i+1],A[i].y=0;
        for(int i=mx;i<len;++i) A[i].x=A[i].y=0;
        fft(A,1);
        for(int i=0;i<mx;++i) B[i].x=r[i+1],B[i].y=0;
        for(int i=mx;i<len;++i) B[i].x=B[i].y=0;
        fft(B,1);
        for(int i=0;i<len;++i) A[i]=A[i]*B[i];
        fft(A,-1);
        for(int i=t;i<=ed;++i) ans+=A[(a[i]<<1)-2].x;
        for(int i=t;i<=ed;++i) l[a[i]]++;
    }
    memset(l,0,sizeof(l));
}

void two()
{
    int ed;
    for(int t=1;t<=n;t+=S)
    {
        ed=min(n,t+S-1);
        for(int j=t;j<ed;++j)
            for(int k=j+1;k<=ed;++k)
                if(a[j]<<1>a[k] && (a[j]<<1)-a[k]<=mx) ans+=l[(a[j]<<1)-a[k]];
        for(int i=t;i<=ed;++i) l[a[i]]++;
    }
    memset(l,0,sizeof(l));
    int t=0,st;
    while(t<n) t+=S;
    t-=S;
    for(int i=t+1;i<=n;++i) r[a[i]]++;
    for(;t>0;t-=S)
    {
        st=t-S+1;
        for(int i=st;i<t;++i)
            for(int j=i+1;j<=t;++j)
                if(a[j]<<1>a[i] && (a[j]<<1)-a[i]<=mx) ans+=r[(a[j]<<1)-a[i]];
        for(int i=st;i<=t;++i) r[a[i]]++;
    }
}

void one()
{
    int ed;
    for(int t=1;t<=n;t+=S)
    {
        ed=min(t+S-1,n);
        for(int j=t;j<=ed;++j)
        {
            for(int k=j+1;k<=ed;++k)
                if(a[j]<<1>a[k] && (a[j]<<1)-a[k]<=mx) ans+=l[(a[j]<<1)-a[k]];
            l[a[j]]++;
        }
        for(int j=t;j<=ed;++j) l[a[j]]--;
    }
}

int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(a[i]),mx=max(mx,a[i]);
    three();
    two();
    one();
    cout<<ans;
}

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8684107.html

时间: 2024-10-26 12:12:36

CodeChef Arithmetic Progressions的相关文章

poj 3006 Dirichlet&#39;s Theorem on Arithmetic Progressions

Description If a and d are relatively prime positive integers, the arithmetic sequence beginning with a and increasing by d, i.e., a, a + d, a + 2d, a + 3d, a + 4d, ..., contains infinitely many prime numbers. This fact is known as Dirichlet's Theore

(素数求解)I - Dirichlet&#39;s Theorem on Arithmetic Progressions(1.5.5)

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description If a and d are relatively prime positive integers, the arithmetic sequence beginning with a and increasing by d, i.e., a, a + d, a + 2d, a + 3d, a 

POJ 3006 Dirichlet&#39;s Theorem on Arithmetic Progressions 素数 难度:0

http://poj.org/problem?id=3006 #include <cstdio> using namespace std; bool pm[1000002]; bool usd[1000002]; bool judge(int x) { if(usd[x])return pm[x]; usd[x] = true; if(x == 2) return pm[x] = true; if(((x & 1) == 0) || (x < 2))return pm[x] =

洛谷P1214 [USACO1.4]等差数列 Arithmetic Progressions

P1214 [USACO1.4]等差数列 Arithmetic Progressions• o 156通过o 463提交• 题目提供者该用户不存在• 标签USACO• 难度普及+/提高 提交 讨论 题解 最新讨论• 这道题有问题• 怎么进一步优化时间效率啊 …题目描述一个等差数列是一个能表示成a, a+b, a+2b,..., a+nb (n=0,1,2,3,...)的数列.在这个问题中a是一个非负的整数,b是正整数.写一个程序来找出在双平方数集合(双平方数集合是所有能表示成p的平方 + q的平

USACO 1.4 Arithmetic Progressions

Arithmetic Progressions An arithmetic progression is a sequence of the form a, a+b, a+2b, ..., a+nb where n=0,1,2,3,... . For this problem, a is a non-negative integer and b is a positive integer. Write a program that finds all arithmetic progression

poj3006 Dirichlet&#39;s Theorem on Arithmetic Progressions

Dirichlet's Theorem on Arithmetic Progressions Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16333   Accepted: 8205 Description If a and d are relatively prime positive integers, the arithmetic sequence beginning with a and increasing

【POJ3006】Dirichlet&#39;s Theorem on Arithmetic Progressions(素数筛法)

简单的暴力筛法就可. 1 #include <iostream> 2 #include <cstring> 3 #include <cmath> 4 #include <cctype> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <numeric> 9 using namespace std; 10 11 co

POJ 3006 Dirichlet&#39;s Theorem on Arithmetic Progressions 快筛质数

题目大意:给出一个等差数列,问这个等差数列的第n个素数是什么. 思路:这题主要考如何筛素数,线性筛.详见代码. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 using namespace std; int prime[MAX],primes; bool notp[MAX]; int a,d,n;

判断素数——Dirichlet&#39;s Theorem on Arithmetic Progressions

Description If a and d are relatively prime positive integers, the arithmetic sequence beginning with a and increasing by d, i.e., a, a + d, a + 2d, a + 3d, a + 4d, ..., contains infinitely many prime numbers. This fact is known as Dirichlet's Theore