HDU 5829 16多校08 Rikka with Subset (NTT)
2017-01-14 17:19
381 查看
题目链接:见这里
题意:给你一个A数组。你要输出所有的T[k]。T[k]是指A数组的所有子集中前k大的数的和的和。
解题思路:先从大到小排序,排序之后发现,第i个数对于k的贡献只当它作为集合中最大,第二大…第k大的时候才有。那么我们可以想一个比较暴力的方法,枚举每个i作为集合第k大的贡献,在求个前缀和,就是答案。设f[k]为所有数作为第k大的时候的和,那么有
![](http://img.blog.csdn.net/20170114171359451?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVzdF9zb3J0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20170114171716330?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanVzdF9zb3J0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
代码如下:
没搞懂为什么一定要用这个原根才可以AC。
题意:给你一个A数组。你要输出所有的T[k]。T[k]是指A数组的所有子集中前k大的数的和的和。
解题思路:先从大到小排序,排序之后发现,第i个数对于k的贡献只当它作为集合中最大,第二大…第k大的时候才有。那么我们可以想一个比较暴力的方法,枚举每个i作为集合第k大的贡献,在求个前缀和,就是答案。设f[k]为所有数作为第k大的时候的和,那么有
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 4e5 + 10; const LL G = 3, P = 998244353; //AC //const LL G = 3, P = 2281701377; //WA //const LL G = 3, P = 2748779069441; //WA LL quick(LL x, LL n) { LL ret = 1; for(; n; n >>= 1) { if(n & 1) ret = ret * x % P; x = x * x % P; } return ret; } 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 op) { rader(y, len); for(int h = 2; h <= len; h <<= 1) { LL wn = quick(G, (P - 1) / h); if(op == -1) wn = quick(wn, P - 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] % P; y[k] = (u + t) % P; y[k + h / 2] = (u - t + P) % P; w = w * wn % P; } } } if(op == -1) { LL inv = quick(len, P - 2); for(int i = 0; i < len; i++) y[i] = y[i] * inv % P; } } LL inv , fac , f , a , b , A ; LL inv2; int n; void pre_init(){ inv2 = quick(2, P - 2); inv[0] = inv[1] = 1; fac[0] = fac[1] = 1; for(LL i = 2; i <= 1e5; i++){ inv[i] = inv[i-1] * quick(i, P-2) % P; fac[i] = fac[i-1] * i % P; } } void solve1(){ //化成做卷积的两个数组 for(int i = 0; i < n; i++){ a[i] = inv[i] * quick(2, n - i) % P; } for(int i = 1; i <= n; i++){ b[i] = fac[i-1] * A[i] % P; } reverse(b+1, b+n+1); for(int i = 0; i < n; i++) b[i] = b[i+1]; b = 0; } void solve2(){ //做ntt 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] % P; ntt(a, len, -1); } void gao(){ //求前缀和,输出答案 LL r = inv2; for(int i = 1; i <= n; i++){ f[i] = r * inv[i-1] % P * a[n-i] % P; f[i] = (f[i-1] + f[i]) % P; printf("%lld ", f[i]); r = r * inv2 % P; //最后一个数后面还有空格 } printf("\n"); } int main() { int T; pre_init(); scanf("%d", &T); while(T--){ scanf("%d", &n); memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(A, 0, sizeof(A)); for(int i = 1; i <= n; i++) scanf("%lld", &A[i]); sort(A + 1, A + n + 1, greater<LL>()); solve1(); solve2(); gao(); } return 0; }
没搞懂为什么一定要用这个原根才可以AC。
相关文章推荐
- flord(传递闭包)
- C++中的模板编程
- 文件包含命令以及C语言预处理概述
- Java利器之UML类图详解
- Plan1
- (17)Powershell中的重定向运算符
- 集合框架_集合多层嵌套的代码体现
- 李白打酒
- 交换最少次数得到回文
- Ubuntu安装mysql
- sping
- 关于locate这个NB命令我不得不深入的学习
- 2 java数组总结
- 最短路计数 洛谷 1114 最短路
- 关于 handler 书写代码 引起的几个问题
- python基础语法(7) 函数2
- SQL Server ->> SQL Server 2016新特性之 --- Query Store
- MVC ---- T4模板的小练习
- 树莓派uboot的串口初始化(uboot驱动结构 2通用解析)
- PAT乙级1056