一開始考慮的是對於每個a
ia_i
ai有哪些a
ja_j
aj與它相乘,但是這樣做不了。
正解是考慮每對(ai
,aj)
(a_i,a_j)
(ai,a
j)的貢獻,然後用fft優化。
首先直接把長度為2
22的給算了,然後剩下的都是奇質數長度。
預處理s
is_i
si表示1
11-i
ii有多少個奇質數。
取模問題,直接long double,最後取模。
分兩種情況:
1、i +j
<=n
+1
i+j<=n+1
i+j<=n
+1。考慮ai×
aj
a_i\times a_j
ai×aj
有多少個,那也就是有多少質數長度的區間中心在i,j
i,ji,
j的中點,稍微寫一寫式子就發現貢獻是ai×
aj×(
si+j
−1−s
∣i−j
∣)
a_i\times a_j\times(s_-s_)
ai×aj
×(s
i+j−
1−s
∣i−j
∣),顯然可以fft。
2、i +j
>
ni+j>n
i+j>n。
寫一寫式子,發現貢獻是ai×
aj×(
s2×n
−(i+
j)+1
−s∣i
−j∣)
a_i\times a_j\times(s_-s)
ai×aj
×(s
2×n−
(i+j
)+1
−s∣i
−j∣)
。然後愉快的發現只用2
22次fft,於是本題就解決了。
#include
using
namespace std;
#define ll long long
#define ld long double
#define pa pair
const
double pi=
acos(-
1.0)
;const
int maxn=
100010
;const
int inf=
2147483647
;const ll mod=
1000000007ll
;int
read()
while
(ch>=
'0'&&ch<=
'9')x=
(x<<3)
+(x<<1)
+(ch^48)
,ch=
getchar()
;return x*f;
}struct c
}a[maxn<<3]
,b[maxn<<3]
;c operator
+(c a,c b)
c operator
-(c a,c b)
c operator
*(c a,c b)
int bin[maxn<<3]
;void
fft(c *a,
int n,
int o)}}
}int n,a[maxn]
;ll ans=0;
int prime[
10000
],len=
0,s[maxn]
;bool mark[maxn]
;void
pre()}
s[2]=
0;for(
int i=
3;i<=n;i++
)s[i]
+=s[i-1]
;}intmain()
memset
(a,0
,sizeof
(a))
;memset
(b,0
,sizeof
(b))
; a[0]
=b[0]=
c(0,
0);for
(int i=
1;i<=n;i++
)a[i]=c
(a[i],0
),b[i]=c
(a[n-i+1]
,0);
fft(a,t,1)
,fft
(b,t,1)
;for
(int i=
0;i<=t;i++
)a[i]
=a[i]
*b[i]
;fft
(a,t,-1
);for(
int i=
1;i<=
(n<<1)
;i++)if
(!(abs
(i-n-1)
&1))
printf
("%lld"
,ans)
;}
51nod 1690 區間求和2
給出乙個長度為n的陣列a。區間 l,r 的值為 r li 0a l i a r i 求所有長度為質數的區間的值的總和。很容易想到,列舉乙個數對,然後統計他的答案 比如說,我們列舉了乙個數對 i j i,j 那麼他的答案的貢獻會有兩種情況 1.i j n 1 i j n 1這個的話,能包含他的區間長度...
51nod 1712 區間求和
解法 這個題首先考慮乙個簡單情況 對於區間 x,y 權值為多少。容易寫出公式 f x y s y s x 1 sum y sum x 1 x 1 sum x 1 y x 1 其中s x 表示 從第乙個元素到第x個元素的 所有有序二元組的和 題目中定義的 sum表示字首和 這裡要求的是所有a x a ...
51nod1680 區間求和(BIT dp)
有n個數,給定乙個k,求所有長度大於等於k的區間中前k大數的總和。這樣就比較簡單相信大家都會,所以此題要求當k 1 n的總和,即求 n k 1 n k 1i 1 nj i k 1 區間前k大和 input 輸入五個數n,a1,a,b,c。a1表示第乙個數,a,b,c用來生成其餘n 1個數。a i a...