HDU first multi-school training 1012 Sequence

Topic links:? Acm.hdu.edu.cn/showproblem.php pid = 6589

The meaning of problems: a given array of length n, there are m times operation, the operator has three 1,2,3, Q array after operation m times, the output i * a [i] and the exclusive OR

K of the substance is calculated once O (n) is, a [i] + = a [ik] (ik> 0)

When k = 1, we can see that this is a prefix and seek operations

When k = 2, we may find that it is 1,3,5,7 ... 2,4,6,8 ... for the two sub-arrays, respectively, is evaluated and operation of the prefix

k = 3, we can see that for 1,4,7,11 3,6,9 ... ... ... 2,5,8,12 three sub-arrays respectively and the prefix seeking operation

The complexity of the violence is O (mn), we can simulate the process of violence, in fact, this process is not a waste of time, because in the game, we sample by checking the program's violence, found a property, that is, change the order of operations, and will not affect the results!

This property is the key to solving problems, if not aware of this nature, it is an unexpected positive solution, then the nature of the problem becomes how to quickly find the m prefix and rough Obviously I thought it was a o (nm) operation, it is not true

Observation seeking process prefix and

0-order (FuMotomu): a [1], a [2], a [3], a [4], a [5] ...

1次:         a[1],a[2]+a[1],a[3]+a[2]+a[1],a[4]+a[3]+a[2]+a[1],a[5]+a[4]+a[3]+a[2]+a[1]...

2次:         a[1],a[2]+2a[1],a[3]+2a[2]+3a[1],a[4]+2a[3]+3a[2]+4a[1],a[5]+2a[4]+3a[3]+4a[2]+5a[1]...

3次:         a[1],a[2]+3a[1],a[3]+3a[2]+6a[1],a[4]+3a[3]+6a[2]+10a[1],a[5]+3a[4]+6a[3]+10a[2]+15a[1]...

...

Here, the law is quite clear, we can find an array of multiple prefixes and after, and it is the result of a combination of several related

M-times, the combination of the array should be c [i] = C (m + i-2, i-1), then the result is represented by an array

m次:      c[1]*a[1],c[1]*a[2]+c[2]*a[1],c[1]*a[3]+c[2]*a[2]+c[3]*a[1],c[1]*a[4]+c[2]*a[3]+c[3]*a[2]+c[4]*a[1],c[1]*a[5]+c[2]*a[4]+c[3]*a[3]+c[4]*a[2]+c[5]*a[1]...

This is already evident thing is the array a [1], a [2], a [3], a [4], a [5] ... and b [1], b [2], b [3 ], b [4], b [5] ... convolved result, the number of combinations of method for finding, O (m) pretreatment, O (1) can be solved, which is a classic approach, here is not then repeat, Baidu many

There are convolved NTT (fast number theory transformation) and FFT (Fast Fourier Transform) two ways, maybe you do not these two methods, it does not matter, sets of templates on the line, for k = 2, k = 3 case we only need to split the array into sub-arrays, you can become a form of k = 1, the problem will be solved

It is worth mentioning, since FFT is a complex operation, the floating point error is present, and is a magic modulo operation (not), where it is more appropriate to use NTT, attention to detail, the board due to repeated use, so each the board must take the time spent inside should reset the data to initialize,

Especially for those seeking a convolution of two arrays! ! !

Do a convolution, we obtain an array of n times and after the prefix, the overall time complexity of O (m + nlogn)

On the code:

#include <bits/stdc++.h>
using namespace std;
#define maxn 300005//注意用来求卷积的数组的大小
#define MOD 998244353
#define mod MOD
#define G 3
typedef long long ll;
namespace NTT {//模板内容
    int rev[maxn], n, m;
    long long A[maxn], B[maxn], C[maxn];

    inline ll Pow(ll a, ll k) {
        ll base = 1;
        while (k) {
            if (k & 1) base = (base * a) % MOD;
            a = (a * a) % MOD;
            k >>= 1;
        }
        return base % MOD;
    }

    void NTT(long long *a, int len, int opt) {
        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) {
            long long wn = Pow(G, (opt * ((MOD - 1) / (i << 1)) + MOD - 1) % (MOD - 1));
            int step = i << 1;
            for (int j = 0; j < len; j += step) {
                long long w = 1;
                for (int k = 0; k < i; k++, w = (1ll * w * wn) % MOD) {
                    long long x = a[j + k];
                    long long y = 1ll * w * a[j + k + i] % MOD;
                    a[j + k] = (x + y) % MOD;
                    a[j + k + i] = (x - y + MOD) % MOD;
                }
            }
        }
        if (opt == -1) {
            long long r = Pow(len, MOD - 2);
            for (int i = 0; i < len; i++)
                a[i] = 1ll * a[i] * r % MOD;
        }
    }

    void solve(int n, int m) {
        int x, l = 0 ,len = 1;
        while (len <= n + m) len <<= 1, ++l;
        for (int i = 0; i < len; ++i)
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
        NTT(A, len, 1), NTT(B, len, 1);
        for (int i = 0; i < len; ++i){
            C[i] = (ll) (A[i] * B[i]) % MOD;
            A[i]=B[i]=0;
        }
        NTT(C, len, -1);
    }
}
template <class T>
void read(T &x) {
    static char ch;static bool neg;
    for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
    for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
    x=neg?-x:x;
}
int n,cnt[4];
ll a[100005],c[100005];
ll fac[1000005],inv[1000005];
ll pow_mod(ll m,ll n)
{
    ll res=1;
    while (n)
    {
        if(n&1)res=res*m%mod;
        m=m*m%mod;
        n>>=1;
    }
    return res;
}
void init()
{
    inv[0]=fac[0]=1;
    for(int i=1;i<=1000000;i++)fac[i]=fac[i-1]*i%mod;
    inv [1000000] = pow_mod (FAC [1000000], v-2);
    for (int I = 999999; I> =. 1; I -) INV [I] = INV [I +. 1] * (I +. 1) MOD%; 
} 
LL C (n-int, int m) 
{ 
    IF (m == 0) return 1; // this place is special treatment to adjust cnt = 0, c array should be this time ... 1,0,0,0,0 
    IF (nm <0) return 0; 
    FAC return [n-] * INV [nm]% MOD INV * [m]% MOD; 
} 
void Calc (int m) // prefix and find the m number of combinations of the array 
{ 
    for (int I =. 1; I <= n- ; I ++) { 
        C [I] = C (m + I-2, I-. 1); 
    } 
} 
int main () 
{ 
    the init (); // number of combinations of pre- 
    int T; 
    CIN >> T; 
    the while (T -) 
    { 
        Memset (CNT, 0, the sizeof (CNT)); 
        int m, OP;  
        Read (n-); Read (m);
        for (int I =. 1; I <= n-; I ++) 
        { 
            Read (A [I]);
        }
        for(int i=1;i<=m;i++)
        {
            read(op);
            ++cnt[op];
        }
        calc(cnt[1]);
        for(int i=0;i<n;i++)NTT::A[i]=a[i+1];
        for(int i=0;i<n;i++)NTT::B[i]=c[i+1];
        NTT::solve(n,n);
        for(int i=0;i<n;i++)a[i+1]=NTT::C[i];
        calc(cnt[2]);
        vector<int>d1,d2,d3;
        for(int i=1;i<=n;i++)
        {
            i%2?d1.emplace_back(a[i]):d2.emplace_back(a[i]);
        }
        for(int i=0;i<d1.size();i++)NTT::A[i]=d1[i];
        for(int i=0;i<d1.size();i++)NTT::B[i]=c[i+1];
        NTT::solve(d1.size(),d1.size());
        for(int i=1;i<=n;i+=2)a[i]=NTT::C[i/2];
        for(int i=0;i<d2.size();i++)NTT::A[i]=d2[i];
        for(int i=0;i<d2.size();i++)NTT::B[i]=c[i+1];
        NTT::solve(d2.size(),d2.size());
        for(int i=2;i<=n;i+=2)a[i]=NTT::C[i/2-1];
        d1.clear();
        d2.clear();
        calc(cnt[3]);
        for(int i=1;i<=n;i++)
        {
            if(i%3==1)d1.emplace_back(a[i]);
            else if(i%3==2)d2.emplace_back(a[i]);
            else d3.emplace_back(a[i]);
        }
        for(int i=0;i<d1.size();i++)NTT::A[i]=d1[i];
        for(int i=0;i<d1.size();i++)NTT::B[i]=c[i+1];
        NTT::solve(d1.size(),d1.size());
        for(int i=1;i<=n;i+=3)a[i]=NTT::C[i/3];
        for(int i=0;i<d2.size();i++)NTT::A[i]=d2[i];
        for(int i=0;i<d2.size();i++)NTT::B[i]=c[i+1];
        NTT::solve(d2.size(),d2.size());
        for(int i=2;i<=n;i+=3)a[i]=NTT::C[i/3];
        for(int i=0;i<d3.size();i++)NTT::A[i]=d3[i];
        for(int i=0;i<d3.size();i++)NTT::B[i]=c[i+1];
        NTT::solve(d3.size(),d3.size());
        for(int i=3;i<=n;i+=3)a[i]=NTT::C[i/3-1];
        ll ans=0;
        for(int i=1;i<=n;i++)ans=ans^(1ll*i*a[i]);
        cout<<ans<<endl;
    }
    return 0;
}

 Standard process gave a better idea, when k = 2, that we have k = 1 c array becomes c [1], 0, c [2], 0, c [3], 0 ... .

When 3 k =, becomes c [1], 0,0, c [2], 0,0, c [3], 0,0 ... which then directly convolved two arrays can be the

It is written in accordance with the standard process the idea of ​​code to streamline a lot, too small a number of constants

#include <bits/stdc++.h>
using namespace std;
#define maxn 300005
#define MOD 998244353
#define mod MOD
#define G 3
typedef long long ll;
int rev[maxn];
long long C[maxn];

inline ll Pow(ll a, ll k) {
    ll base = 1;
    while (k) {
        if (k & 1) base = (base * a) % MOD;
        a = (a * a) % MOD;
        k >>= 1;
    }
    return base % MOD;
}

void NTT(long long *a, int len, int opt) {
    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) {
        long long wn = Pow(G, (opt * ((MOD - 1) / (i << 1)) + MOD - 1) % (MOD - 1));
        int step = i << 1;
        for (int j = 0; j < len; j += step) {
            long long w = 1;
            for (int k = 0; k < i; ++k, w = (1ll * w * wn) % MOD) {
                long long x = a[j + k];
                long long y = 1ll * w * a[j + k + i] % MOD;
                a[j + k] = (x + y) % MOD;
                a[j + k + i] = (x - y + MOD) % MOD;
            }
        }
    }
    if (opt == -1) {
        long long r = Pow(len, MOD - 2);
        for (int i = 0; i < len; i++)
            a[i] = 1ll * a[i] * r % MOD;
    }
}

void solve(ll A[],ll B[],int n, int m) {
    int x, l = 0 ,len = 1;
    while (len <= n + m) len <<= 1, ++l;
    for (int i = 0; i < len; ++i)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    NTT(A, len, 1), NTT(B, len, 1);
    for (int i = 0; i < len; ++i) {
        C[i] = (ll) (A[i] * B[i]) % MOD;
        A[i] = B[i] = 0;
    }
    NTT(C, len, -1);
}
void read(ll &x) {
    static char ch;static bool neg;
    for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
    for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
    x=neg?-x:x;
}
int n,cnt[4];
ll a[maxn],c[maxn];
ll fac[1000005],inv[1000005];
ll pow_mod(ll m,ll n)
{
    ll res=1;
    while (n)
    {
        if(n&1)res=res*m%mod;
        m=m*m%mod;
        n>>=1;
    }
    return res;
}
void init()
{
    inv[0]=fac[0]=1;
    for(int i=1;i<=1000000;i++)fac[i]=fac[i-1]*i%mod;
    inv[1000000]=pow_mod(fac[1000000],mod-2);
    for(int i=999999;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
ll Comb(int n,int m)
{
    return n<m?0:fac[n]*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
    init();//组合数预处理
    int T;
    cin>>T;
    while (T--)
    {
        memset(cnt,0, sizeof(cnt));
        ll m,op;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            read(a[i]);
        }
        for(int i=1;i<=m;i++)
        {
            read(op);
            ++cnt[op];
        }
        for(int i=1;i<=3;i++)
        {
            memset(c,0, sizeof(c));
            for(int j=0;j*i<n;j++)
            {
                c[j*i]=Comb(cnt[i]-1+j,j);
            }
            if(cnt[i]==0)c[0]=1;//特殊处理
            solve(a+1,c,n,n);
            for(int i=0;i<n;i++)a[i+1]=C[i];
        }
        ll ans=0;
        for(int i=1;i<=n;i++)ans=ans^(1ll*i*a[i]);
        cout<<ans<<endl;
    }
    return 0;
}

Summary: Overall, this problem is not difficult, although the process is cumbersome, time in the game with a FFT did not write it, but the total harvest is still very large, for the time before this match had a few questions helpless, now also own a 7788 analysis of, it is progress

Think more, do not give up easily, perhaps the next moment will be able to harvest AC!

 

Guess you like

Origin www.cnblogs.com/xusirui/p/11229450.html