天天看点

HDU 5829 16多校08 Rikka with Subset (NTT)

Rikka with Subset

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 871    Accepted Submission(s): 276

Problem Description

As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has n numbers A[1]~A[n] and a number K. For any none empty subset S of the numbers, the value of S is equal to the sum of the largest min(|S|,k) numbers in S. The value of the array A is equal to the sum of the value of all none empty subset of the numbers.

Now Yuta shows the n numbers, And he wants to know the value of the array for each K in [1,n].

It is too difficult for Rikka. Can you help her?

Input

The first line contains a number t(1<=t<=10), the number of the testcases.

For each testcase, the first line contains a number n(1<=n<=100000), the number of numbers Yuta has. The second line contains n number A[1]~A[n](0<=A[i]<=10^9).

Output

For each testcase, print a line contains exactly n numbers, the ith number is the value of the array when K=i. The answer may be very large, so you only need to print the answer module 998244353.

Sample Input

2
3
1 1 1
5
1 2 3 4 5      

Sample Output

7 11 12
129 201 231 239 240      

Author

学军中学

Source

​​2016 Multi-University Training Contest 8​​

Recommend

wange2014   |   We have carefully selected several similar problems for you:  ​​5932​​​ ​​5931​​​ ​​5930​​​ ​​5929​​​ ​​5928​​

题意:给你一个A数组。你要输出所有的T[k]。T[k]是指A数组的所有子集中前k大的数的和的和。

题解:FFT的原理,NTT的板子(P需要是费马素数...有空我再写一篇NTT(快速数论变换)的文章吧....

假设一个数g对于P来说是原根,那么

HDU 5829 16多校08 Rikka with Subset (NTT)

的结果两两不同,且有 1<g<P,0<i<P,那么g可以称为是P的一个原根,归根到底就是

HDU 5829 16多校08 Rikka with Subset (NTT)

当且仅当指数为P-1的时候成立.(这里P是素数).

所以这时就可以利用卷积来解决了。

先从大到小排序,排序之后发现,第i个数对于k的贡献只当它作为集合中最大,第二大…第k大的时候才有。那么我们可以想一个比较暴力的方法,枚举每个i作为集合第k大的贡献,在求个前缀和,就是答案。

设f[k]为所有数作为第k大的时候的和,那么有

HDU 5829 16多校08 Rikka with Subset (NTT)

HDU 5829 16多校08 Rikka with Subset (NTT)

HDU 5829 16多校08 Rikka with Subset (NTT)

以上就是卷积的套路了。设

HDU 5829 16多校08 Rikka with Subset (NTT)

 ,

HDU 5829 16多校08 Rikka with Subset (NTT)

。先把b数组reverse一下,

HDU 5829 16多校08 Rikka with Subset (NTT)

,再整体左移一位就是

HDU 5829 16多校08 Rikka with Subset (NTT)

。此时就是卷积形式了。注意最后是

HDU 5829 16多校08 Rikka with Subset (NTT)

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int inf = 0x3f3f3f3f;
const int maxn = 4e5 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;
const ll mod = 998244353;
const ll g = 3; // MOD的原根,当且仅当 g^(MOD-1) = 1 % MOD
ll Pow(ll a, ll n)
{
    ll ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % mod;
        n >>= 1;
        a = a * a % mod;
    }
    return ans;
}
void rader(ll y[], int len)
{
    for(int i = 1, j = len / 2; i < len - 1; i++){
        if(i < j) swap(y[i], y[j]);
        int k = len / 2;
        while(j >= k) {
            j -= k;
            k /= 2;
        }
        if(j < k) j += k;
    }
}
void ntt(ll y[], int len, int on) //NTT
{
    rader(y, len);
    for(int h = 2; h <= len; h <<= 1){
        ll wn = Pow(g, (mod-1)/h);
        if(on == -1) wn = Pow(wn, mod-2);
        for(int j = 0; j < len; j += h) {
            ll w = 1;
            for(int k = j; k < j + h / 2; k++) {
                ll u = y[k];
                ll t = w * y[k + h / 2] % mod;
                y[k] = (u + t) % mod;
                y[k+h/2] = (u - t + mod) % mod;
                w = w * wn % mod;
            }
        }
    }
    if(on == -1) {
        ll t = Pow(len, mod - 2);
        for(int i = 0; i < len; i++)
            y[i] = y[i] * t % mod;
    }
}
ll inv[maxn];
ll fac[maxn];
ll f[maxn];
ll inv2;
ll a[maxn], b[maxn];
ll A[maxn];
int n;
void init()
{
    inv2 = Pow(2, mod - 2);
    inv[1] = inv[0] = 1;
    fac[0] = fac[1] = 1;
    for(ll i = 2; i <= 1e5; i++)
    {
        inv[i] = inv[i-1] * Pow(i, mod - 2) % mod;
        fac[i] = fac[i-1] * i % mod;
    }
}
void solve()
{
    for(int i = 0; i < n; i++)
    {
        a[i] = inv[i] * Pow(2, n-i) % mod;
    }
    for(int i = 1; i <= n; i++)
    {
           b[i] = fac[i-1] * A[i] % mod;
    }
    reverse(b+1, b+1+n);
    for(int i = 0; i < n; i++)
    {
        b[i] = b[i+1];
    }
    b[n] = 0;
}
void Conv()
{
    int len = 1;
    while(len <= 2*n) len <<= 1;
    ntt(a, len, 1);
    ntt(b, len, 1);
    for(int i = 0; i < len; i++)
    {
        a[i] = a[i] * b[i] % mod;
    }
    ntt(a, len, -1);
}
void gao()
{
    ll r = inv2;
    for(int i = 1; i <= n; i++)
    {
        f[i] = r * inv[i-1] % mod * a[n-i] % mod;
        f[i] = (f[i-1] + f[i]) % mod;
        printf("%lld ", f[i]);
        r = r * inv2 % mod;
    }
    puts(""); //最后一个数后也有空格..... 
}

int main()
{

    int t;
    scanf("%d", &t);
    init();
    while(t--)
    { 
        scanf("%d", &n);
        memset(A, 0, sizeof(A));
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        for(int i = 1; i <= n; i++)
        {
            scanf("%lld", &A[i]);
        }
        sort(A+1, A+n+1, greater<ll>()); 
        solve();     
        Conv();        
        gao();
    }
    return 0;
}