zoukankan      html  css  js  c++  java
  • [loj2473]秘密袭击

    容易发现答案即$sum_{S}sum_{u=1}^{W}[ule val(S)]=sum_{u=1}^{W}sum_{S}[ule val(S)]$,那么可以枚举权值$u$,并将点权$val<u$的点标为0,$ule val$的点标为1,相当于统计大于等于k个1的连通子图个数
    考虑dp,用$f[u][i][j]$表示权值为u,在以i为根的子树中,选出点中恰好有j个1的方案数,转移方程为$f[u][i][j]=sum_{a[i]+sum_{son}b[son]=j}prod_{son}(f[u][son][b[son]]+[b[son]==0])$,复杂度为$o(wcdot n^{3})$
    令$F[u][i](x)=sum_{j=0}^{sz[i]}f[u][i][j]cdot x^{j}$,那么$F[u][i](x)=x^{a[i]}prod_{son}(F[u][son](x)+1)$,对其插值,最后再用拉格朗日插值法求出系数(先把所有多项式加起来再求),复杂度为$o(wcdot n^{2})$
    调换枚举顺序,对于一个插值,将每一个点i以u为下标建立一棵线段树,由于如果i子树内不存在某一个权值w,那么显然有$F[w][i]=F[w-1][i]$,因此可以线段树合并来实现dp过程,总复杂度$o(n^{2}log W)$
    由于线段树合并时还需要实现累加子树内的多项式,这可以通过记录4个标记$(a,b,c,d)$来实现,其中a和b表示这个点的答案,c和d表示累加起来的答案,最后标记都下传后的d标记即为这个位置上所有数的和
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 2005
      4 #define mod 64123
      5 #define mid (l+r>>1)
      6 struct ji{
      7     int nex,to;
      8 }edge[N<<1];
      9 struct tag{
     10     int a,b,c,d;
     11 }f[N*15];
     12 int V,E,n,m,w,v,x,y,ans,head[N],r[N],a[N],b[N],sum[N],ch[N*15][2];
     13 void add(int x,int y){
     14     edge[E].nex=head[x];
     15     edge[E].to=y;
     16     head[x]=E++;
     17 }
     18 int ksm(int n,int m){
     19     if (!m)return 1;
     20     int s=ksm(n,m>>1);
     21     s=1LL*s*s%mod;
     22     if (m&1)s=1LL*s*n%mod;
     23     return s;
     24 }
     25 int New(){
     26     f[++V]=tag{1,0,0,0};
     27     ch[V][0]=ch[V][1]=0;
     28     return V;
     29 }
     30 void upd(int &k,tag x){
     31     if (!k)k=New();
     32     f[k].c=(1LL*f[k].a*x.c+f[k].c)%mod;
     33     f[k].d=(1LL*f[k].b*x.c+f[k].d+x.d)%mod;
     34     f[k].a=1LL*f[k].a*x.a%mod;
     35     f[k].b=(1LL*f[k].b*x.a+x.b)%mod;
     36 }
     37 void down(int k){
     38     upd(ch[k][0],f[k]);
     39     upd(ch[k][1],f[k]);
     40     f[k]=tag{1,0,0,0};
     41 }
     42 void update(int &k,int l,int r,int x,int y,tag z){
     43     if ((l>y)||(x>r))return;
     44     if (!k)k=New();
     45     if ((x<=l)&&(r<=y)){
     46         upd(k,z);
     47         return;
     48     }
     49     down(k);
     50     update(ch[k][0],l,mid,x,y,z);
     51     update(ch[k][1],mid+1,r,x,y,z);
     52 }
     53 int merge(int k1,int k2){
     54     if ((!k1)||(!k2))return k1+k2;
     55     if ((!ch[k1][0])&&(!ch[k1][1]))swap(k1,k2);
     56     if ((!ch[k2][0])&&(!ch[k2][1])){
     57         f[k1].a=1LL*f[k1].a*f[k2].b%mod;
     58         f[k1].b=1LL*f[k1].b*f[k2].b%mod;
     59         f[k1].d=(f[k1].d+f[k2].d)%mod;
     60         return k1;
     61     }
     62     down(k1);
     63     down(k2);
     64     ch[k1][0]=merge(ch[k1][0],ch[k2][0]);
     65     ch[k1][1]=merge(ch[k1][1],ch[k2][1]);
     66     return k1;
     67 }
     68 void dfs(int k,int fa){
     69     upd(r[k],tag{0,1,0,0});
     70     for(int i=head[k];i!=-1;i=edge[i].nex)
     71         if (edge[i].to!=fa){
     72             dfs(edge[i].to,k);
     73             r[k]=merge(r[k],r[edge[i].to]);
     74         }
     75     update(r[k],1,w,1,a[k],tag{v,0,0,0});
     76     upd(r[k],tag{1,0,1,0});
     77     upd(r[k],tag{1,1,0,0});
     78 }
     79 void tot(int k,int l,int r){
     80     if (l==r){
     81         sum[v]=(sum[v]+f[k].d)%mod;
     82         return;
     83     }
     84     down(k);
     85     tot(ch[k][0],l,mid);
     86     tot(ch[k][1],mid+1,r);
     87 }
     88 int main(){
     89     scanf("%d%d%d",&n,&m,&w);
     90     memset(head,-1,sizeof(head));
     91     for(int i=1;i<=n;i++)scanf("%d",&a[i]); 
     92     for(int i=1;i<n;i++){
     93         scanf("%d%d",&x,&y);
     94         add(x,y);
     95         add(y,x);
     96     }
     97     for(v=0;v<=n;v++){
     98         V=0;
     99         memset(r,0,sizeof(r));
    100         dfs(1,0);
    101         tot(r[1],1,w);
    102     }
    103     memset(a,0,sizeof(a));
    104     a[0]=1;
    105     for(int i=0;i<=n;i++)
    106         for(int j=i+1;j>=0;j--)a[j]=(a[j-1]-i*a[j]%mod+mod)%mod;
    107     for(int i=0;i<=n;i++){
    108         x=1;
    109         for(int j=0;j<=n;j++)
    110             if (i!=j)x=1LL*x*(i-j+mod)%mod;
    111         x=1LL*ksm(x,mod-2)*sum[i]%mod;
    112         memcpy(b,a,sizeof(b));
    113         for(int j=n+1;j;j--){
    114             b[j-1]=(b[j-1]+i*b[j])%mod;
    115             if (m<j)ans=(ans+1LL*b[j]*x)%mod;
    116         }
    117     }
    118     printf("%d",ans);
    119 }
    View Code
  • 相关阅读:
    计算欧拉函数值
    矩阵快速幂
    约瑟夫环数学公式
    整型输出输入优化
    计算机设计第三章
    计算机设计第二章
    计算机设计
    阿里巴巴秋招2017客户端附加题
    程序设计基本概念
    c++面试题
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/12923078.html
Copyright © 2011-2022 走看看