当前位置: 代码迷 >> 综合 >> 51nod 1690 区间求和2
  详细解决方案

51nod 1690 区间求和2

热度:27   发布时间:2023-10-29 06:36:18.0

题意

给出一个长度为n的数组a。区间[L,R]的值为 ∑R?Li=0a[L+i]?a[R?i]
求所有长度为质数的区间的值的总和。

题解

很容易想到,枚举一个数对,然后统计他的答案
比如说,我们枚举了一个数对(i,j)(i,j)
那么他的答案的贡献会有两种情况
1.i+j<=n+1i+j<=n+1
这个的话,能包含他的区间长度是[j?i+1,j?i+1+2?(i?1)][j?i+1,j?i+1+2?(i?1)]
化简一下式子可以的得到[j?i+1,j+i?1][j?i+1,j+i?1]
也就是他的答案的贡献是a[i]?a[j]?(s[i+j?1]?s[j?i])a[i]?a[j]?(s[i+j?1]?s[j?i])
ss表示质数个数的前缀和
然后这个显然可以用FFT处理
然后对于 i + j > n + 1 的情况也是同理
这里就不写了
有一个要注意的地方就是,你要保证(i,j)(i,j)合法,也就是要让(i,j)(i,j)同奇偶
在计算的时候,我们不把2当作质数
最后单独算就行
然后取模什么的不用管。。
最后模就行
用double会炸精度,所以要开long double
CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
typedef long double LB;
const LB pi=M_PI;
const LL MOD=1e9+7;
const LL N=100005*10;
struct qq {LB x,y;qq (){}qq (LB _x,LB _y)    {
   x=_x;y=_y;}
};
qq operator + (qq x,qq y)   {
   return qq(x.x+y.x, x.y+y.y);}
qq operator - (qq x,qq y)   {
   return qq(x.x-y.x, x.y-y.y);}
qq operator * (qq x,qq y)   {
   return qq(x.x*y.x-x.y*y.y, x.x*y.y+x.y*y.x);}
LL bin[N];
void fft (qq *a,LL n,LL o)
{for (LL u=0;u<n;u++) bin[u]=(bin[u>>1]>>1)|((u&1)*(n>>1));for (LL u=1;u<n;u++)if (u<bin[u])swap(a[u],a[bin[u]]);for (LL u=1;u<n;u<<=1){qq wn=qq(cos(2*pi/(u<<1)),o*sin(2*pi/(u<<1)));for (LL i=0;i<n;i+=(u<<1)){qq w=qq(1,0);for (LL j=0;j<u;j++){qq t=w*a[u+i+j];a[u+i+j]=a[i+j]-t;a[i+j]=a[i+j]+t;w=w*wn;}}}
}
LL n;
LL f[N];
LL pri[N],tot;
bool ok[N];
void prepare ()
{memset(ok,true,sizeof(ok));ok[1]=false;for (LL u=2;u<=n;u++){if (ok[u])  pri[++tot]=u;for (LL i=1;i<=tot;i++){LL j=pri[i];if (j*u>n) break;ok[j*u]=false;if (u%j==0) break;}}ok[2]=false;for (LL u=1;u<=n;u++) f[u]=f[u-1]+ok[u];
}
LL ans=0;
LL a[N];
qq b[N],c[N];
LL g[N];//储存所有i+j=k的s[i]*s[j] 
void solve ()//统计情况 
{memset(b,0,sizeof(b));memset(c,0,sizeof(c));LL nn=n*2,now;now=1;while (now<=nn) now<<=1; now<<=1;//for (LL u=0;u<now;u++) b[u]=c[u]=qq(0,0);for (LL u=1;u<=n;u++) b[n+u].x=a[u];for (LL u=1;u<=n;u++) c[n-u].x=a[u];fft(b,now,1);fft(c,now,1);for (LL u=0;u<now;u++) b[u]=b[u]*c[u];fft(b,now,-1);for (LL u=0;u<=n;u++)   if (u%2==0)ans=(ans-(f[u]*(LL)(b[u+nn].x/now+0.5))%MOD)%MOD;if (ans<0) ans+=MOD;ans=ans*2%MOD;//printf("%lld\n",ans);/*i+j<=n+1*/memset(b,0,sizeof(b));memset(c,0,sizeof(c));for (LL u=1;u<=n;u++) b[u].x=a[u];for (LL u=1;u<=n;u++) c[u].x=a[u];now=1;while (now<=nn) now<<=1;fft(b,now,1);fft(c,now,1);for (LL u=0;u<now;u++) b[u]=b[u]*c[u];fft(b,now,-1);for (LL u=0;u<=nn;u++) g[u]=(LL)(b[u].x/now+0.5);for (LL u=1;u<=n+1;u++)//i+j=uif (u%2==0)ans=(ans+g[u]*f[u-1]%MOD)%MOD;for (LL u=n+1;u<=nn;u++)if (u%2==0)ans=(ans+g[u]*f[nn+1-u]%MOD)%MOD;
}
int main()
{//freopen("a.in","r",stdin);scanf("%lld",&n);prepare();/*for (LL u=1;u<=n;u++) printf("%lld ",f[u]);printf("\n");*/for (LL u=1;u<=n;u++) scanf("%lld",&a[u]);solve();for (LL u=1;u<n;u++)    ans=(ans+a[u]*a[u+1]*2%MOD)%MOD;printf("%lld\n",ans);return 0;
}