首页 > 其他分享 >P3784 [SDOI2017] 遗忘的集合

P3784 [SDOI2017] 遗忘的集合

时间:2023-11-04 15:25:34浏览次数:35  
标签:mod1 mod2 mod3 const limits sum SDOI2017 P3784 遗忘

传送门

description

对于一个元素都 \(\leq n\) 的正整数集合 \(S\)(不含相同元素),\(f(i)\) 表示使用集合 \(S\) 里的数加和为 \(i\) 的方案数,每个元素可以被使用多次,两个方案不同当且仅当存在一个元素在两种方案中使用次数不同。

现给定 \(n\) 和 \(f(i),1\leq i\leq n\)。

求出集合 \(|S|\) 的大小并给出字典序最小的 \(S\)。

solution

先反着考虑给定集合 \(S\) 怎么求出 \(f(i)\)。

设 \(f_{i,j}\) 表示用 \(S\) 里前 \(i\) 个元素构成和为 \(j\) 的方案数,设 \(S\) 中第 \(i\) 个元素为 \(a_i\)。有转移:

  • \(f_{0,0}=1\)

  • \(f_{i,j}=\sum\limits_{k\ge 0} f_{i-1,j-ka_i}\)

设 \(F_i(x)\) 是 \(\{f_{i,j}\}_{j=0}^{+ \infty}\) 的生成函数,根据转移式,有 \(F_{|S|}(x)=\prod\limits_{i=1}^{|S|}(1+x^{a_i}+x^{2a_i}+x^{3a_i}+\dots)\)。

根据经典套路,右边取 \(\ln\) 得,\(\ln(F_{|S|}(x))=\sum\limits_{i=1}^{|S|}\ln(1+x^{a_i}+x^{2a_i}+x^{3a_i}+\dots)=\sum\limits_{i=1}^{|S|}\ln(\dfrac{1}{1-x^{a_i}})\)。

根据 \(\ln(1-x)=-\sum\limits_{i\ge 1}\dfrac{x^i}{i}\) 得,\(\ln(F_{|S|}(x))=\sum\limits_{i=1}^{|S|}\sum\limits_{j\ge 1} \dfrac{x^{ja_i}}{j}\)。

右边调换一下求和顺序,\(\sum\limits_{p=1}x^p\sum\limits_{d\mid p} A_{d}\dfrac{d}{p}\),其中 \(A_d\) 表示 \(d\) 是否在集合 \(S\) 中。

归纳地,假设已经求出所有 \(A_{i},1\leq i<t\),我们当然能求出 \(A_t\),直接枚举从小到大 \(d\) 并枚举它的倍数即可,时间复杂度 \(O(n\ln n)\)。

带上多项式求 \(\ln\),时间复杂度 \(O(n\log n)\)。

我用的之前写的 3 模数 NTT 求逆板子,常数比较大,不过轻松跑,一发就过了。(这题 5s 时限)。

顺便说一下,根据我们构造 \(S\) 的方法可以知道,如果数据保证有解,那么 \(S\) 一定唯一。

code

#include<bits/stdc++.h>

using namespace std;

typedef long long E;
typedef unsigned __int128 lint;
const E mod1=998244353,mod2=469762049,mod3=1004535809,_g=3;
const int N=(1<<19)+9;
const lint P=(lint)mod1*mod2*mod3;

struct Ei{
    E a,b,c;

    Ei(){

    }

    Ei (E x,E y,E z){
        a=x,b=y,c=z;
    }

    Ei(E x){
        a=b=c=x;
    }

    friend Ei operator +(const Ei &x,const Ei &y){
        Ei z;
        z.a=x.a+y.a>=mod1?x.a+y.a-mod1:x.a+y.a;
        z.b=x.b+y.b>=mod2?x.b+y.b-mod2:x.b+y.b;
        z.c=x.c+y.c>=mod3?x.c+y.c-mod3:x.c+y.c;
        return z;
    }

    friend Ei operator -(const Ei &x,const Ei &y){
        Ei z;
        z.a=x.a<y.a?x.a-y.a+mod1:x.a-y.a;
        z.b=x.b<y.b?x.b-y.b+mod2:x.b-y.b;
        z.c=x.c<y.c?x.c-y.c+mod3:x.c-y.c;
        return z;
    }

    friend Ei operator *(const Ei &x,const Ei &y){
        Ei z;
        z.a=x.a*y.a%mod1;
        z.b=x.b*y.b%mod2;
        z.c=x.c*y.c%mod3;
        return z;
    }
};

inline E ksm(E a,E b,E mod){
    E ret=1;
    if(a>=mod) a%=mod;
    if(b>=mod-1||b<0) b=(b%(mod-1)+mod-1)%(mod-1);
    while(b){
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}


const lint inv1=ksm(mod2*mod3%mod1,mod1-2,mod1);
const lint inv2=ksm(mod1*mod3%mod2,mod2-2,mod2);
const lint inv3=ksm(mod1*mod2%mod3,mod3-2,mod3);
const lint p1=P/mod1*inv1%P,p2=P/mod2*inv2%P,p3=P/mod3*inv3%P;
E mod=1e9+7;

void wr(lint x){
    if(x>9) wr(x/10);
    putchar('0'+x%10);
}

void CRT(Ei *a,int n){
    for(int i=0; i<n; i++){
        lint ans=0;
        ans=(ans+(lint)a[i].a*p1);
        ans=(ans+(lint)a[i].b*p2);
        ans=(ans+(lint)a[i].c*p3)%P;
        a[i]=ans%mod;
    }
}

int rev[N],lstn;

inline void prework(int n){
    if(lstn==n) return ;
    for(int i=1; i<n; i++) rev[i]=(rev[i^(i&-i)]|(1<<(__lg(n)-1-__lg(i&-i))));
    return lstn=n,void();
}

void ntt(Ei *p,int n,int op){
    prework(n);
    for(int i=1; i<n; i++){
        if(i<rev[i]) swap(p[i],p[rev[i]]);
    }

    for(int i=2; i<=n; i<<=1){
        int len=i>>1;
        Ei w=(Ei){ksm(_g,op*(mod1-1)/i,mod1),ksm(_g,op*(mod2-1)/i,mod2),ksm(_g,op*(mod3-1)/i,mod3)};
        for(int pos=0; pos<n; pos+=i){
            Ei now=1ll;
            for(int j=pos; j<pos+len; j++,now=now*w){
                Ei u=p[j],v=now*p[j+len];
                p[j]=u+v,p[j+len]=u-v;
            }
        }
    }

    if(op==-1){
        Ei tmp=(Ei){ksm(n,mod1-2,mod1),ksm(n,mod2-2,mod2),ksm(n,mod3-2,mod3)};
        for(int i=0; i<n; i++){
            p[i]=p[i]*tmp;
        }
    }
}

void px(Ei *a,Ei *b,int n){
    for(int i=0; i<n; i++) a[i]=a[i]*b[i];
}

#define clr(f,n) memset(f,0,sizeof(Ei)*n)
#define cpy(f,g,n) memcpy(f,g,sizeof(Ei)*n)

void polyinv(Ei *a,Ei *b,int n){
    static Ei now[N],r[N];
    b[0]=ksm(a[0].a,mod-2,mod);
    for(int len=2; len<=n; len<<=1){
        int t=len>>1;
        for(int i=0; i<t; i++){
            r[i]=b[i].a*2%mod;
        }
        cpy(now,a,len);
        ntt(now,len<<1,1),ntt(b,len<<1,1);
        px(now,b,len<<1);
        ntt(now,len<<1,-1);
        clr(now+len,len);
        CRT(now,len);
        for(int i=0; i<(len); i++) now[i]=(mod-now[i].a)%mod;

        ntt(now,len<<1,1);
        px(now,b,len<<1);
        ntt(now,len<<1,-1);
        clr(now+len,len);
        CRT(now,len);
        for(int i=0; i<len; i++){
            b[i]=(r[i].a+now[i].a>=mod?r[i].a+now[i].a-mod:r[i].a+now[i].a);
        }
        clr(b+len,len);
    }
    clr(now,n<<1),clr(r,n<<1);
}


inline void polyln(Ei *a,Ei *b,int n){
  static Ei tmp[N];
  clr(b,n<<1); clr(tmp,n<<1);
  polyinv(a,tmp,n);
  for(int i=0; i<n; i++){
    b[i]=a[i+1].a*(i+1)%mod;
  }
  ntt(b,n<<1,1),ntt(tmp,n<<1,1);
  px(b,tmp,n<<1);
  ntt(b,n<<1,-1);
  clr(b+n,n);
  CRT(b,n);
  for(int i=n-1; i; i--){
    b[i]=b[i-1].a*ksm(i,mod-2,mod)%mod;
  }
  b[0]=0;
}

E a[N],b[N],n,m,INV[N];
Ei A[N],B[N];

int main(){

  cin>>n>>mod;
  INV[1]=1;
  for(int i=2; i<=n; i++) INV[i]=(mod-mod/i)*1ll*INV[mod%i]%mod;
  for(int i=1; i<=n; i++) scanf("%lld",a+i);
  a[0]=1;
  for(int i=0; i<=n; i++) A[i]=a[i];
  int t;
  for(t=1;t<=n;t<<=1) ;
  polyln(A,B,t);
  for(int i=1; i<=n; i++) b[i]=B[i].a;

  for(int i=1; i<=n; i++){
    for(int j=i*2; j<=n; j+=i){
      b[j]=(b[j]-b[i]*INV[j/i]%mod+mod)%mod;
    }
  }

  vector<int> ans;
  for(int i=1; i<=n; i++){
    if(b[i]!=0) ans.emplace_back(i);
  }

  cout<<ans.size()<<endl;
  for(auto p:ans) printf("%lld ",p);

  return 0;
}

P.S.

好像代码里递推部分最开始写成 \(\log^2\) 了(调和级数套快速幂),改成线性预处理逆元之后快了 10s 多。

标签:mod1,mod2,mod3,const,limits,sum,SDOI2017,P3784,遗忘
From: https://www.cnblogs.com/FreshOrange/p/17809368.html

相关文章

  • 解题报告 P3704 [SDOI2017] 数字表格
    P3704[SDOI2017]数字表格经典莫反。题目要求:\[\prod_{i=1}^n\prod_{j=1}^mfib(\gcd(i,j))\]不妨令\(n<m\)。套路地,我们设\(\gcd(i,j)=d\),然后枚举\(d\):\[\begin{aligned}&\quad\prod_{d=1}^n\prod_{i=1}^n\prod_{j=1}^mfib(d)^{[\gcd(i,j)==d]}\\&=\pr......
  • 金碟星空云 sql server常用表(防遗忘)
    数据表命名基本规则:表名前缀:t_或者T_视图前缀:v_或者V_多语言表后缀:_L关联关系表后缀:_LK一、元数据元数据:t_meta_objectType元数据扩展信息表:t_meta_objectType_E元数据缓存表:T_META_OBJECTTYPECACHE元数据视图表:T_META_OBJECTTYPEVIEW元数据视图:V_META_OBJECTTYPE_L元......
  • 王道408---CO---计算机系统概述易混淆易遗忘知识点
    易混淆性能指标机器字⻓计算机进⾏⼀次整数运算所能处理的⼆进制的位数,⼀般与字⻓⻓度有关注意不是浮点数运算数据通路带宽外部数据总线⼀次能并⾏传送信息的位数,⾮CPU内部数据总线宽度MIPSMIPS:每秒执⾏多少百万条指令MFLOPS:每秒执⾏多少百万次浮点运算GFLOPS:每秒执⾏多......
  • P3780 [SDOI2017] 苹果树 题解
    DescriptionP3780[SDOI2017]苹果树给定一棵\(n\)个点的树,每个点有若干个价值相同的苹果,儿子能摘至少一个仅当父亲被摘至少一个。给定\(k\),设\(h\)为你摘的苹果的最大深度,你做多能摘\(k+h\)个,求最大价值。对于所有数据,\(1\len\le5\times10^4\),\(1\lek\le5\time......
  • [SDOI2017] 数字表格
    传送门跟YY的gcd如出一辙,得到一个显然的柿子\[\prod_{k}F_{k}^{z}\]\[z=\sum_{d}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor\]那么我们设T=kd,\[\prod_{T}\prod_{k|T}F_{k}^x\]\[x=\mu(\frac{T}{k})\lfloor\frac{n}{T}\rfloor\lfl......
  • P3704 [SDOI2017] 数字表格 题解
    一、题目描述:用$f_i$表示斐波那契数列的第$i$项,那么有:$f_0=0,f_1=1;f_n=f_{n-1}+f_{n-2},n\ge2$现在有一个$n$行$m$列的数字表格,第$i$行第$j$列的数字是$f_{\gcd(i,j)}$。求这个表格所有数的乘积。共有$T$组数据,答案对$10^9+7$取模。......
  • 遗忘的教训:关注细节,珍惜当下
    周末聚餐是生活中的一种美好体验,大家可以围坐在餐桌旁,品尝各式佳肴,畅谈人生、工作、兴趣等话题。而这次聚餐中,商家还送了一些小玩具在餐桌上,增添了许多童真和快乐。可是,我们在享受美食和欢声笑语的同时,也有些隐忧。果不其然,我把一个小玩具放在餐桌旁,本来想着吃完饭收拾好了再带回......
  • 前端遗忘知识点
    #JS1.基本数据类型numberstringbooleanundefindnullbigintsymbol2.交互alertconfirm确认prompt带输入的确认3.Object.assign(a,b,c)进行合并将a,b,c中的同名属性进行合并4.计算属性名可以将变量的计算结果作为属性的名称```letname="firstname"letperson={......
  • [SDOI2017]数字表格
    题意求如下表达式的值\[\prod_{i=1}^{n}\prod_{j=1}^{m}f_{gcd(i,j)}\pmod{10^9+7}\]其中,\(f_i\)为fibonacci数列的第\(i\)项,\(n,m\leqslant10^6\)Solution\[\prod_{i=1}^{n}\prod_{j=1}^{m}f_{gcd(i,j)}\]改变枚举顺序,优先枚举\(d=gcd(i,j)\),\[=\prod_{d=1}......
  • P3704 [SDOI2017]数字表格
    简要题意令\(f(i)\)为斐波那契数列第\(i\)项的值。\(T\)组数据,对于每一个\(n,m\),求出:\[\prod_{i=1}^{n}\prod_{j=1}^{m}f(\gcd(i,j))\pmod{10^9+7}\]\(1\leqT\leq10^3,1\leqn,m\leq10^6\)思路这里将介绍一种自认为比题解更为简便的方法首先原式有\(\prod\)......