luogu4365 秘密襲擊 (生成函數+線段樹合並+拉格朗日插值)
求所有可能聯通塊的第k大值的和,考慮枚舉這個值:
$ans=\sum\limits_{i=1}^{W}{i\sum\limits_{S}{[i是第K大]}}$
設cnt[i]為連通塊中值>=i的個數
$ans=\sum\limits_{i=1}^{W}{i\sum\limits_{S}{[cnt[i]>=K]-[cnt[i+1]>=K]}}$
$ans=\sum\limits_{i=1}^{W}{\sum\limits_{S}{[cnt[i]>=K]}}$
於是先考慮樹上dp,設f[i][j][k]表示以i為根的連通塊中,值>=j的數量為k的情況數
然後$ans=\sum\limits_{i=1}^{N}{\sum\limits_{j=1}^{W}{\sum\limits_{k=K}^{N}{f[i][j][k]}}}$
轉移和背包類似,所以這樣做是$O(N^2W)$的
考慮使用生成函數優化,設$F[i][j]=\sum{f[i][j][k]x^k}$,再設$G[i][j]=\sum{F[s][j]},i是s的祖先$
於是轉移就變成了$F[i][j]*=(F[s][j]+1),G[i][j]+=G[s][j],G[i][j]+=F[i][j]$,其中s是i的孩子
同時有初值$F[i][j]=(d[i]>=j?x:1)$,答案就是G[1][*]的K~N項系數的和
然後當然不能真的去乘了..
考慮先將F和G用點值表達,最後再插回來
首先枚舉x=1..N+1,然後給每個點i開動態開點的線段樹維護F[i][j]和G[i][j]的值
然後用線段樹合並來做對應位置的相乘和相加
具體來說,我們讓線段樹上的結點維護一個作用在$(f,g)$上的變換$(a,b,c,d)$,使得最終得到$(af+b,cf+d+g)$
然後也不難得到變換的乘法(有結合律但沒有交換律)
然後就可以做了 復雜度我也不會分析 反正有可能跑的比暴力還慢
別忘了回收掉不用的點
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 #define MP make_pair 5#define fi first 6 #define se second 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 typedef unsigned int ui; 11 typedef long double ld; 12 const int maxn=1700,maxp=3e6; 13 const int P=64123; 14 15 inline char gc(){ 16 return getchar(); 17 static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf; 18 return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++; 19 } 20 inline ll rd(){ 21 ll x=0;char c=gc();bool neg=0; 22 while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=1;c=gc();} 23 while(c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+c-‘0‘,c=gc(); 24 return neg?(~x+1):x; 25 } 26 27 struct Node{ 28 int a,b,c,d; 29 Node(int _a=1,int _b=0,int _c=0,int _d=0){a=_a,b=_b,c=_c,d=_d;} 30 }val[maxp]; 31 Node operator *(Node x,Node y){ 32 return Node(1ll*x.a*y.a%P,(1ll*x.b*y.a+y.b)%P,(1ll*x.a*y.c+x.c)%P,(1ll*x.b*y.c+x.d+y.d)%P); 33 } 34 35 int N,K,W,dan[maxn],eg[maxn*2][2],egh[maxn],ect; 36 int ch[maxp][2],stk[maxp],sh,rt[maxn]; 37 int yy[maxn]; 38 39 inline void adeg(int a,int b){ 40 eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect; 41 } 42 43 inline int newnode(){ 44 int p=stk[sh--]; 45 assert(sh>=1); 46 ch[p][0]=ch[p][1]=0; 47 val[p]=Node(); 48 return p; 49 } 50 51 inline void delall(int &p){ 52 if(!p) return; 53 delall(ch[p][0]);delall(ch[p][1]); 54 stk[++sh]=p;p=0; 55 } 56 57 inline void pushdown(int p){ 58 if(!ch[p][0]) ch[p][0]=newnode(); 59 if(!ch[p][1]) ch[p][1]=newnode(); 60 val[ch[p][0]]=val[ch[p][0]]*val[p]; 61 val[ch[p][1]]=val[ch[p][1]]*val[p]; 62 val[p]=Node(); 63 } 64 65 void mul(int &p,int l,int r,int x,int y,Node z){ 66 if(!p) p=newnode(); 67 if(x<=l&&r<=y){ 68 val[p]=val[p]*z; 69 }else{ 70 int m=(l+r)>>1;pushdown(p); 71 if(x<=m) mul(ch[p][0],l,m,x,y,z); 72 if(y>=m+1) mul(ch[p][1],m+1,r,x,y,z); 73 } 74 } 75 76 int merge(int &p,int &q){ 77 if(!p||!q) return p|q; 78 if(!ch[p][0]&&!ch[p][1]) swap(p,q); 79 if(!ch[q][0]&&!ch[q][1]){ 80 val[p]=val[p]*Node(val[q].b,0,0,val[q].d); 81 return p; 82 } 83 pushdown(p),pushdown(q); 84 ch[p][0]=merge(ch[p][0],ch[q][0]); 85 ch[p][1]=merge(ch[p][1],ch[q][1]); 86 return p; 87 } 88 89 void dfs(int x,int f,int id){ 90 mul(rt[x],1,W,1,W,Node(0,1,0,0)); 91 for(int i=egh[x];i;i=eg[i][1]){ 92 int b=eg[i][0];if(b==f) continue; 93 dfs(b,x,id); 94 merge(rt[x],rt[b]); 95 delall(rt[b]); 96 } 97 mul(rt[x],1,W,1,dan[x],Node(id,0,0,0)); 98 mul(rt[x],1,W,1,W,Node(1,0,1,0)); 99 mul(rt[x],1,W,1,W,Node(1,1,0,0)); 100 } 101 102 int query(int p,int l,int r){ 103 if(!p) return 0; 104 if(l==r) return val[p].d; 105 int m=(l+r)>>1;pushdown(p); 106 return (query(ch[p][0],l,m)+query(ch[p][1],m+1,r))%P; 107 } 108 109 int fpow(int x,int y){ 110 int r=1; 111 while(y){ 112 if(y&1) r=1ll*r*x%P; 113 x=1ll*x*x%P,y>>=1; 114 }return r; 115 } 116 117 int l[maxn],tmp[maxn],ans[maxn]; 118 void calc(){ 119 l[0]=1; 120 for(int i=1;i<=N+1;i++){ 121 for(int j=i-1;j>=0;j--){ 122 l[j+1]=(l[j+1]+l[j])%P; 123 l[j]=-1ll*i*l[j]%P; 124 } 125 } 126 for(int i=1;i<=N+1;i++){ 127 int ib=-fpow(i,P-2); 128 tmp[0]=1ll*l[0]*ib%P; 129 for(int j=1;j<=N;j++){ 130 tmp[j]=1ll*(l[j]-tmp[j-1])*ib%P; 131 } 132 int k=0,x=1; 133 for(int j=0;j<=N;j++){ 134 k=(1ll*x*tmp[j]+k)%P; 135 x=1ll*x*i%P; 136 } 137 k=1ll*fpow(k,P-2)*yy[i]%P; 138 for(int j=0;j<=N;j++){ 139 ans[j]=(1ll*tmp[j]*k+ans[j])%P; 140 } 141 } 142 } 143 144 int main(){ 145 //freopen("","r",stdin); 146 N=rd(),K=rd(),W=rd(); 147 for(int i=1;i<=N;i++) dan[i]=rd(); 148 for(int i=1;i<N;i++){ 149 int a=rd(),b=rd(); 150 adeg(a,b);adeg(b,a); 151 } 152 for(int i=1;i<maxp-5;i++) stk[++sh]=i; 153 154 for(int i=1;i<=N+1;i++){ 155 dfs(1,0,i); 156 yy[i]=query(rt[1],1,W); 157 delall(rt[1]); 158 } 159 calc(); 160 int a=0; 161 for(int i=K;i<=N;i++) a=(a+ans[i])%P; 162 printf("%d\n",(a+P)%P); 163 return 0; 164 }
luogu4365 秘密襲擊 (生成函數+線段樹合並+拉格朗日插值)