4836: [Lydsy2017年4月月賽]二元運算

4836: [Lydsy2017年4月月賽]二元運算

Time Limit: 8 Sec Memory Limit: 128 MB
Submit: 286 Solved: 92
[Submit][Status][Discuss]
Description

定義二元運算 opt 滿足
這裏寫圖片描述

現在給定一個長爲 n 的數列 a 和一個長爲 m 的數列 b ,接下來有 q 次詢問。每次詢問給定一個數字 c
你需要求出有多少對 (i, j) 使得 a_i opt b_j=c 。
Input

第一行是一個整數 T (1≤T≤10) ,表示測試數據的組數。
對於每組測試數據:
第一行是三個整數 n,m,q (1≤n,m,q≤50000) 。
第二行是 n 個整數,表示 a_1,a_2,?,a_n (0≤a_1,a_2,?,a_n≤50000) 。
第三行是 m 個整數,表示 b_1,b_2,?,b_m (0≤b_1,b_2,?,b_m≤50000) 。
第四行是 q 個整數,第 i 個整數 c_i (0≤c_i≤100000) 表示第 i 次查詢的數。
Output

對於每次查詢,輸出一行,包含一個整數,表示滿足條件的 (i, j) 對的個數。

Sample Input

2

2 1 5

1 3

2

1 2 3 4 5

2 2 5

1 3

2 4

1 2 3 4 5
Sample Output

1

0

1

0

0

1

0

1

0

1
HINT

Source

鳴謝Tangjz提供試題

[Submit][Status][Discuss]

先考慮aibj 的情形
考慮到每個數字不超過50000 ,記c=50000,bi=cbi
那麼,ai+bj=c+aibj
定義Ai 爲數組a 中數字i 出現的次數
然後讓AB 做卷積,其中第i 項係數就是差值爲ic 的數量了
所以有用的係數都是大於等於50000 的項
這一部分的複雜度爲O(klogk)
不過對於ai<bj 的情形就不能這樣了
考慮對值域分治然後做卷積
每次在A 中填入[l,mid]B 中填入[mid+1,r]
這樣做卷積就能避開所有非法情形了
這一部分複雜度O(klog2k)
很科學對不對,很科學對不對???

這裏寫圖片描述

我也不知道爲什麼。。。。反正真的卡了好久好久的常數
以及一開始的幾個TLE ,其實答案也是錯的。。不過根本跑不完
首先,這道題卡什麼都卡得喪心病狂
模數用1004535809 是根本不夠的
於是百度找到了這個3221225473 ,原根是5
存儲得用unsigned int 平方得用unsigned long long
然後開始解決漫長的卡常數問題。。。

  1. 千萬不要在NTT 過程中寫很多除法,klog2k 次不是開玩笑的
  2. 傳指針可能有些慢?所以分開來寫兩種NTT
  3. 隨意試了一下發現,讓初始值域爲[0,65535] 使得每一層值域大小都爲2k 能夠顯著提升效率
  4. 用三目運算符配合加減法加速加法和減法的取模

於是乎終於卡過了。。。(不過還是非常非常慢的)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn = (1 << 17);
typedef long long LL;
typedef unsigned int u32;
typedef unsigned long long u64;
const u32 W = 1;
const u32 TT = 10;
const u64 WW = 1;
const u32 mo = 3221225473LL;

int n,m,q,T,A[maxn],B[maxn],ca[maxn],cb[maxn],f[maxn],g[maxn],LOG[maxn + 1];
u32 Ans[maxn],w[maxn + 1],_w[maxn + 1],Inv[maxn + 233],a[maxn],b[maxn],c[maxn];

#define Mul(x,y) (WW * (x) * (y) % mo)
#define max(a,b) ((a) > (b) ? (a) : (b))
#define swap(x,y) ((x) ^= (y),(y) ^= (x),(x) ^= (y))
#define Dec(x,y) ((x) < (y) ? (x) + mo - (y) : (x) - (y))
#define Add(x,y) (mo - (x) > (y) ? (x) + (y) : (x) - mo + (y))

inline u32 ksm(u32 x,u32 y)
{
    u32 ret = W;
    for (; y; y >>= W)
    {
        if (y & W) ret = Mul(ret,x);
        x = Mul(x,x);
    }
    return ret;
}

inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}

char s[20];
inline void Print(u32 x)
{
    if (!x) {puts("0"); return;} int len = 0;
    while (x) s[++len] = x % TT,x /= TT;
    for (int i = len; i; i--) putchar(s[i] + '0'); puts("");
}

inline void Rader(u32 *F,int N)
{
    int j = (N >> 1);
    for (int i = 1; i < N - 1; i++)
    {
        if (i < j) swap(F[i],F[j]); int k = (N >> 1);
        while (j >= k) j -= k,k >>= 1; j += k;
    }
}

inline void NTT(u32 *F,int N)
{
    Rader(F,N);
    for (int k = 2; k <= N; k <<= 1)
    {
        int tmp = k >> 1,G = maxn / k;
        for (int i = 0; i < N; i += k)
        {
            int now = 0;
            for (int j = i; j < i + tmp; j++)
            {
                u32 u = F[j],v = Mul(w[now],F[j + tmp]);
                F[j] = Add(u,v); F[j + tmp] = Dec(u,v); now += G;
            }
        }
    }
}

inline void _NTT(u32 *F,int N)
{
    Rader(F,N);
    for (int k = 2; k <= N; k <<= 1)
    {
        int tmp = k >> 1,G = maxn / k;
        for (int i = 0; i < N; i += k)
        {
            int now = 0;
            for (int j = i; j < i + tmp; j++)
            {
                u32 u = F[j],v = Mul(_w[now],F[j + tmp]);
                F[j] = Add(u,v); F[j + tmp] = Dec(u,v); now += G;
            }
        }
    }
    for (int i = 0; i < N; i++) F[i] = Mul(F[i],Inv[N]);
}

inline void Work()
{
    int N = 131072,t = 65536;
    for (int i = 1; i <= n; i++) ++a[A[i]];
    for (int i = 1; i <= m; i++) ++b[t - B[i]];
    NTT(a,N); NTT(b,N);
    for (int i = 0; i < N; i++) c[i] = Mul(a[i],b[i]); _NTT(c,N);
    for (int i = t; i < N; i++) Ans[i - t] += c[i];
    for (int i = 0; i < N; i++) a[i] = b[i] = c[i] = 0;
}

inline void Calc(int l,int r)
{
    if (l == r) return;
    int mid = l + r >> 1,M = r - l + 1 << 1,tf = 0,tg = 0;
    for (int i = l; i <= mid; i++)
        if (ca[i]) a[i - l] = ca[i],f[++tf] = i;
    for (int i = mid + 1; i <= r; i++)
        if (cb[i]) b[i - l] = cb[i],g[++tg] = i;
    if (1LL * tf * tg > 1LL * M * LOG[M])
    {
        NTT(a,M); NTT(b,M);
        for (int i = 0; i < M; i++) c[i] = Mul(a[i],b[i]); _NTT(c,M);
        for (int i = 0; i < M; i++) Ans[i + l * 2] += c[i],a[i] = b[i] = c[i] = 0;
    }
    else
    {
        for (int i = 1; i <= tf; i++)
            for (int j = 1; j <= tg; j++)
                Ans[f[i] + g[j]] += W * ca[f[i]] * cb[g[j]];
        for (int i = 1; i <= tf; i++) a[f[i] - l] = 0;
        for (int i = 1; i <= tg; i++) b[g[i] - l] = 0;
    }
    Calc(l,mid); Calc(mid + 1,r);
}

inline void Solve()
{
    n = getint(); m = getint(); q = getint();
    for (int i = 1; i <= n; i++) A[i] = getint(),++ca[A[i]];
    for (int i = 1; i <= m; i++) B[i] = getint(),++cb[B[i]];
    Work(); Calc(0,65535); while (q--) Print(Ans[getint()]);
}

inline void Clear()
{
    memset(ca,0,sizeof(ca));
    memset(cb,0,sizeof(cb));
    memset(Ans,0,sizeof(Ans));
}

int main()
{
    #ifdef DMC
        freopen("binop1.in","r",stdin);
        freopen("test.out","w",stdout);
    #endif

    w[0] = 1; w[1] = ksm(5,(mo - 1) / maxn);
    for (int i = 2; i <= maxn; i++) w[i] = Mul(w[i - 1],w[1]);
    for (int i = 0; i <= maxn; i++) _w[i] = w[maxn - i];
    for (int i = 1; i <= maxn; i <<= 1) Inv[i] = ksm(i,mo - 2);
    for (int i = 2; i <= maxn; i <<= 1) LOG[i] = LOG[i >> 1] + 1;
    T = getint(); while (T--) Solve(),Clear();
    return 0;
}
發佈了730 篇原創文章 · 獲贊 20 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章