[bzoj 3509] [CodeChef] COUNTARI - 블록 FFT
#include
using namespace std;
#define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for(int i = a , _ = b ; i < _ ; i ++)
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
inline void upmax(int&a , int b) { if (a < b) a = b; }
inline void upmin(int&a , int b) { if (a > b) a = b; }
typedef long long ll;
const int maxn = 110007;
const int maxs = 61007;
const int maxb = 307;
const int len = 1823;
typedef int arr[maxn];
typedef int blk[maxb];
typedef int num[maxs];
arr a , belong , L , R;
blk st , ed;
num cnt[maxb] , cnt_nxt , cnt_pre;
ll ans;
int n , tot , lim;
void input() {
n = rd();
rep (i , 1 , n) a[i] = rd() , upmax(lim , a[i]);
}
inline void init_block() {
rep (i , 1 , n) belong[i] = (i - 1) / len + 1;
tot = belong[n];
rep (i , 1 , tot) st[i] = (i - 1) * len + 1 , ed[i] = i * len;
upmin(ed[tot] , n);
rep (i , 1 , tot) {
rep (j , st[i] , ed[i])
cnt[i][a[j]] ++;
}
}
const int maxN = 524299;
struct comp {
long double real , imag;
comp(long double real = 0 , long double imag = 0):real(real) , imag(imag) { }
inline friend comp operator+(comp&a , comp&b)
{ return comp(a.real + b.real , a.imag + b.imag); }
inline friend comp operator-(comp&a , comp&b)
{ return comp(a.real - b.real , a.imag - b.imag); }
inline friend comp operator*(comp&a , comp&b)
{ return comp(a.real * b.real - a.imag * b.imag , a.imag * b.real + a.real * b.imag); }
inline friend void swap(comp&a , comp&b)
{ comp c = a ; a = b ; b = c; }
}A[maxN];
int rev[maxN] , N , Nlen;
ll res[maxN];
inline void FFT_clear() {
memset(A , 0 , sizeof(comp) * N);
}
inline void FFT_init() {
for (N = 1 , Nlen = 0;N <= lim + lim;N <<= 1 , Nlen ++) ;
For (i , 1 , N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << Nlen - 1);
}
const long double ppi = std::acos(-1.0) * 2;
inline void FFT(comp*a , int n , int v) {
For (i , 0 , n) if (i < rev[i]) swap(a[i] , a[rev[i]]);
for (int s = 2;s <= n;s <<= 1) {
comp g(cos(ppi / s) , v * sin(ppi / s));
for (int k = 0;k < n;k += s) {
comp w(1 , 0);
For (j , 0 , s / 2) {
comp t = a[k + j + s / 2] * w , u = a[k + j];
a[k + j + s / 2] = u - t , a[k + j] = u + t;
w = w * g;
}
}
}
if (v == -1) For (i , 0 , n)
a[i].real /= n * 4, a[i].imag /= n;
}
inline void GetConv() {
FFT_clear();
rep (i , 0 , lim) A[i] = comp(L[i] + R[i] , L[i] - R[i]);
FFT(A , N , 1);
For (i , 0 , N) A[i] = A[i] * A[i];
FFT(A , N , -1);
for (int i = 0;i <= lim + lim;i += 2) res[i] = (ll) (A[i].real + 0.5);
}
inline void calc(int p) {
int t = a[p] + a[p];
int cur = belong[p];
rep (i , st[cur] , p - 1) if (t >= a[i])
ans += R[t - a[i]];
rep (i , p + 1 , ed[cur]) if (t >= a[i]) {
ans += cnt_pre[t - a[i]];
ans += L[t - a[i]];
if (cur == 1) continue;
}
if (p <= ed[1] || p >= st[tot]) return;
ans += res[t];
}
void solve() {
init_block();
FFT_init();
rep (i , 1 , n) R[a[i]] ++;
rep (i , 1 , tot) {
memset(cnt_pre , 0 , sizeof(int) * (lim + 1));
rep (j , st[i] , ed[i]) cnt_nxt[a[j]] ++;
rep (j , 0 , lim) R[j] -= cnt[i][j];
if (i != 1 && i != tot)
GetConv();
rep (j , st[i] , ed[i]) cnt_nxt[a[j]] -- , calc(j) , cnt_pre[a[j]] ++;
rep (j , 0 , lim) L[j] += cnt[i][j];
}
printf("%lld
" , ans);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
freopen("data.out" , "w" , stdout);
#endif
input();
solve();
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
수열 블록 입문 1 ~ 9 문제 풀이그렇지 않 으 면 전체 블록 에 대해 t a g tag 를 직접 수정 하고 다른 분산 요소 에 대해 a [i] a [i] a [i] a [i] a [i] 를 직접 폭력 적 으로 수정 합 니 다. 분산 요소 에 대해 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.