2021HDU多校7 - 7054 Yiwen with Formula(分治MTT优化dp)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021HDU多校7 - 7054 Yiwen with Formula(分治MTT优化dp)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的数列 a a a,现在需要求 ∏ b 1 < b 2 < ⋯ < b k ( a b 1 + a b 2 + ⋯ + a b k ) \\prod_{b_1<b_2<\\cdots<b_k} (a_{b_1}+a_{b_2}+\\cdots+a_{b_k}) b1<b2<<bk(ab1+ab2++abk)

需要满足:

  1. 1 ≤ b i ≤ n 1 \\leq b_i \\leq n 1bin
  2. b 1 < b 2 < ⋯ < b k b_1<b_2<\\cdots<b_k b1<b2<<bk
  3. k ≥ 1 k \\geq 1 k1

简单题意:需要求 a a a 数列的所有子序列之和之积

题目分析:一个非常重要的转换就是,设 c [ k ] c[k] c[k]子序列之和 k k k 的子序列的方案数,那么答案显然就是 ∏ k c [ k ] \\prod k^{c[k]} kc[k],又因为题目保证了 ∑ a i ≤ 1 e 5 \\sum a_i\\le1e5 ai1e5,也就是 k k k 的上限不超过 1 e 5 1e5 1e5,所以我们现在的问题是如何求出数组 c [ k ] c[k] c[k]

一个很简单的背包思想就是 d p [ i ] [ j ] dp[i][j] dp[i][j] 代表前 i i i 个数字所选子序列之和为 j j j 的方案数, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − a [ i ] ] dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i]] dp[i][j]=dp[i1][j]+dp[i1][ja[i]],转移是 O ( n 2 ) O(n^2) O(n2) 的,最终 c [ i ] = d p [ n ] [ i ] c[i]=dp[n][i] c[i]=dp[n][i]

考虑写成生成函数的形式,即 F ( x ) = ( 1 + x a 1 ) ( 1 + x a 2 ) ⋯ ( 1 + x a n ) F(x)=(1+x^{a_1})(1+x^{a_2})\\cdots(1+x^{a_n}) F(x)=(1+xa1)(1+xa2)(1+xan),那么 c [ i ] c[i] c[i] 就是 F ( x ) F(x) F(x) x i x^i xi 的系数了,暴力求解的话仍然是 O ( n 2 ) O(n^2) O(n2)

考虑分治FFT优化,这样复杂度就下降为 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

需要注意的是,我们最终的答案是需要求解 ∏ k c [ k ] ( m o d p ) \\prod k^{c[k]}\\pmod {p} kc[k](modp),而这里的 c [ k ] c[k] c[k] 在计算过程中也是需要取模的。因为本题的 p = 998244353 p=998244353 p=998244353 是质数,根据费马小定理降幂,得到 ∏ k c [ k ] ( m o d p ) = ∏ k c [ k ] ( m o d p − 1 ) ( m o d p ) \\prod k^{c[k]}\\pmod {p}=\\prod k^{c[k]\\pmod{p-1}}\\pmod {p} kc[k](modp)=kc[k](modp1)(modp) 推得 c c c 数组是需要对 p − 1 p-1 p1 取模的,但这并不是一般的模数,所以不能用 N T T NTT NTT,只能用 M T T MTT MTT 去实现

代码也是参考了 s t d std std 的结构体封装的动态分配数组,实现的太巧妙了

代码:

// Problem: Yiwen with Formula
// Contest: Virtual Judge - HDU
// URL: https://vjudge.net/problem/HDU-7054
// Memory Limit: 524 MB
// Time Limit: 16000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
    T f=1;x=0;
    char ch=getchar();
    while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=f;
}
template<typename T>
inline void write(T x)
{
    if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e5+100;
const int mod=998244353;
const int BASE=1<<15;
const long double Pi=acos(-1.0);
struct complex
{
    long double x,y;
    complex (long double xx=0,long double yy=0){x=xx,y=yy;}
}P1[N<<2],P2[N<<2],Q[N<<2];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}
int limit以上是关于2021HDU多校7 - 7054 Yiwen with Formula(分治MTT优化dp)的主要内容,如果未能解决你的问题,请参考以下文章

[2019杭电多校第一场][hdu6578]Blank

hdu5379||2015多校联合第7场1011 树形统计

杭电多校2019.7.24--暑假集训

HDU多校2017第7场

HDU 6124 17多校7 Euler theorem(简单思维题)

HDU-6395多校7 Sequence(除法分块+矩阵快速幂)