3.15 模拟赛
T1 1e5只龙的故事
题目大意:
一棵树 q次询问 每次询问一条路径上的第$k$小的点的权值(不去重),然后把整个路径上所有点的权值都改成这个值
思路:
好暴力啊
使用树剖线段树暴力维护权值一样的区间 查询的时候开个数组记录所有满足条件的区间 排序后直接查即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 180100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt,val[MAXN],tag[MAXN<<2]; 31 int sz[MAXN],dep[MAXN],fa[MAXN],hvs[MAXN],bl[MAXN],in[MAXN],tot; 32 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 33 void dfs(int x,int pa) 34 { 35 sz[x]=1,fa[x]=pa;ren if(to[i]^pa) 36 {dep[to[i]]=dep[x]+1;dfs(to[i],x);sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x];} 37 } 38 void Dfs(int x,int anc) 39 { 40 bl[x]=anc,in[x]=++tot;if(!hvs[x]) return ;Dfs(hvs[x],anc); 41 ren if(to[i]^fa[x]&&to[i]^hvs[x]) Dfs(to[i],to[i]); 42 } 43 struct ask{int x,v;}res[MAXN];int top; 44 void pshd(int k) {if(tag[k]) tag[k<<1]=tag[k<<1|1]=tag[k],tag[k]=0;} 45 void mdf(int k,int l,int r,int a,int b,int x) 46 { 47 if(l==a&&r==b) {tag[k]=x;return ;}int mid=l+r>>1;pshd(k); 48 if(b<=mid) mdf(k<<1,l,mid,a,b,x);else if(a>mid) mdf(k<<1|1,mid+1,r,a,b,x); 49 else {mdf(k<<1,l,mid,a,mid,x);mdf(k<<1|1,mid+1,r,mid+1,b,x);} 50 } 51 void query(int k,int l,int r,int a,int b) 52 { 53 if(l==a&&r==b&&tag[k]) {res[++top]=(ask){tag[k],r-l+1};return ;}int mid=l+r>>1;pshd(k); 54 if(b<=mid) query(k<<1,l,mid,a,b);else if(a>mid) query(k<<1|1,mid+1,r,a,b); 55 else {query(k<<1,l,mid,a,mid);query(k<<1|1,mid+1,r,mid+1,b);} 56 } 57 bool cmp(ask a,ask b){return a.x<b.x;} 58 int Query(int a,int b,int k) 59 { 60 for(top=0;bl[a]!=bl[b];a=fa[bl[a]]) 61 {if(dep[bl[a]]<dep[bl[b]]) swap(a,b);query(1,1,n,in[bl[a]],in[a]);} 62 if(in[a]>in[b]) swap(a,b);query(1,1,n,in[a],in[b]); 63 sort(res+1,res+top+1,cmp);int sum=0;rep(i,1,top) {sum+=res[i].v;if(sum>=k) return res[i].x;} 64 } 65 void work(int a,int b,int k) 66 { 67 for(;bl[a]!=bl[b];a=fa[bl[a]]) 68 {if(dep[bl[a]]<dep[bl[b]]) swap(a,b);mdf(1,1,n,in[bl[a]],in[a],k);} 69 if(in[a]>in[b]) swap(a,b);mdf(1,1,n,in[a],in[b],k); 70 } 71 int main() 72 { 73 n=read();int a,b,x=read(),y=read(),MOD=read(); 74 rep(i,1,n) val[i]=read();rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a); 75 int q=read(),k;dfs(1,0);Dfs(1,1);rep(i,1,n) mdf(1,1,n,in[i],in[i],val[i]); 76 while(q--) 77 {a=read(),b=read(),k=read();k=Query(a,b,k);printf("%d\n",k);work(a,b,pls(mul(k,x),y)+1);} 78 }
T2 小R的箱子
题目大意:
每个箱子有长$x$和宽$y$,只有满足$a.x<=b.x$且$a.y<=b.y$才能把$a$装进$b$内(不能交换x y
且每个箱子里只能装一个,但是可以嵌套。
思路:
每个箱子向可以装它的箱子连边,费用为起点箱子的面积
把每个点拆成两个点,分别与$S$,$T$连边来限制流量,跑一个最大费用流
用总费用去减即可
这样就需要去重,所有相等的看做一个,其余的直接装进去(否则两个相等的会互相装
(原来一直以来我的费用流都是假的,自闭了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 510 15 #define MAXM 40100 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,x[MAXN],y[MAXN],S,T,ban[MAXN]; 32 struct ZKW 33 { 34 int fst[MAXN],to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cos[MAXM<<1],cnt; 35 int dis[MAXN],vis[MAXN],res; 36 ZKW() {res=0,cnt=1;memset(fst,0,sizeof(fst));} 37 void add(int u,int v,int w,int c) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w,cos[cnt]=c;} 38 void ins(int u,int v,int w,int c) {add(u,v,w,c);add(v,u,0,-c);} 39 int spfa() 40 { 41 memset(dis,127,sizeof(dis)); 42 queue<int> q; 43 dis[T]=0,vis[T]=1;q.push(T); 44 while(!q.empty()) 45 { 46 int x=q.front();q.pop();vis[x]=0; 47 for(int i=fst[x];i;i=nxt[i]) 48 if(val[i^1]&&dis[to[i]]>dis[x]-cos[i]) 49 { 50 dis[to[i]]=dis[x]-cos[i]; 51 if(!vis[to[i]]) {q.push(to[i]);vis[to[i]]=1;} 52 } 53 } 54 return dis[S]!=inf; 55 } 56 int dfs(int x,int a) 57 { 58 if(x==T||!a) {res+=dis[S]*a;return a;} 59 if(vis[x])return 0; 60 vis[x]=1; 61 int res=0,f; 62 for(int i=fst[x];i&&a;i=nxt[i]) 63 if(val[i]&&dis[to[i]]==dis[x]-cos[i]&&(f=dfs(to[i],min(a,val[i])))) 64 res+=f,val[i]-=f,val[i^1]+=f,a-=f; 65 return res; 66 } 67 void solve(int flw=0) 68 { 69 int f;while(spfa()) 70 do{memset(vis,0,sizeof(vis));f=dfs(S,inf),flw+=f;}while(f); 71 } 72 }Z; 73 int main() 74 { 75 n=read();rep(i,1,n) x[i]=read(),y[i]=read();S=(n<<1)+10,T=S+1;int sum=0; 76 rep(i,1,n) rep(j,i+1,n) if(x[i]==x[j]&&y[i]==y[j]) ban[max(j,i)]=1; 77 rep(i,1,n) rep(j,1,n) if(i!=j&&x[i]<=x[j]&&y[i]<=y[j]&&ban[i]==0&&ban[j]==0) Z.ins(i,j+n,1,-x[i]*y[i]); 78 rep(i,1,n) if(!ban[i]) Z.ins(S,i,1,0),Z.ins(i+n,T,1,0),sum+=x[i]*y[i]; 79 Z.solve(); 80 printf("%d\n",sum+Z.res); 81 }
T3 绯红之王
题目大意:
已知数列$a$,求$\sum\limits_{i=1}^n {a_i}^k$
思路:
很久以前讲过的题,调了一年才搞出来
首先设$f_k=\sum\limits_{i=1}^n {a_i}^k$ , $g_k$表示对于所有$C_n^k$种选择的方法,$g_k=$所有方法内各个数相乘的和
例如数列中有四个数$a,b,c,d$ 则
$g_0=1$
$g_1=a+b+c+d$
$g_2=ab+ac+ad+bc+bd+cd$
$g_3=abc+abd+acd+bcd,g_4=abcd$
我们可以发现
$f_2=f_1 * g_1 - 2g_2$
$f_3=f_2 * g_1 - f_1* g_2 + 3g_3$
$f_4=f_3*g_1-f_2*g_2+f_1*g_3-4g_4$
发现下标为偶数的$g$都变成了其相反数,而且这是一个$f_0$在变化的分治$NTT$形式
那么我们将$f_0$设为0,在$cdq$到$l==r$时,再加上这个$n*g_n$贡献
现在考虑如何计算$g$数组,因为$g_i$是齐次轮换对称式 可以通过计算两部分再合并
例如$h_0=1,h_1=a+b+c,h_2=ab+ac+bc,h_3=abc$
$t_0=1,t_1=d+e+f,t_2=de+df+ed,t_3=def$
则$g_0=h_0*t_0=1$
$g_1=h_0*t_1+h_1*t_0$
$g_2=h_0*t_2+h_1*t_1+h_2*t_0$
$......$
这样可以维护一个类似线段树的结构来计算$g$,即一开始每个点有一个自己的多项式$1,a_i$
然后一层一层往上合并,计算出$g$后再用分治$NTT$来计算$f$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 800100 15 #define MOD 998244353 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (1LL*a%MOD+b%MOD+MOD)%MOD 21 #define mns(a,b) (1LL*a%MOD-b%MOD+MOD)%MOD 22 #define mul(a,b) ((ll)(1LL*(a))%MOD*(b)%MOD)%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,rev[MAXN],l2[MAXN],pw[MAXN],A[MAXN],B[MAXN],aa[MAXN]; 32 int g[MAXN],f[MAXN]; 33 vector<int> vec[MAXN]; 34 int q_pow(int bas,int t,int res=1) 35 { 36 for(;t;bas=mul(bas,bas),t>>=1) 37 if(t&1) res=mul(res,bas);return res; 38 } 39 void ntt(int *a,int n,int f) 40 { 41 rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]); 42 for(int i=1;i<n;i<<=1) 43 { 44 int wn=pw[i<<1];if(f==-1) wn=q_pow(wn,MOD-2); 45 for(int j=0;j<n;j+=i<<1) 46 { 47 int w=1,x,y; 48 for(int k=0;k<i;k++,w=mul(w,wn)) 49 x=a[k+j],y=mul(a[i+j+k],w),a[j+k]=pls(x,y),a[i+j+k]=mns(x,y); 50 } 51 } 52 if(f==1) return ;int nv=q_pow(n,MOD-2); 53 rep(i,0,n-1) a[i]=mul(a[i],nv); 54 } 55 void solve(int *a,int *b,int lmt) 56 { 57 ntt(a,lmt,1);ntt(b,lmt,1);rep(i,0,lmt-1) a[i]=mul(a[i],b[i]); 58 ntt(a,lmt,-1); 59 } 60 void Div(int l,int r,ll lmt=0) 61 { 62 if(l==r) return ;int mid=(l+r)>>1,lg; 63 Div(l,mid);Div(mid+1,r);lg=l2[r-l+1]+1,lmt=1<<lg; 64 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),A[i]=B[i]=0; 65 rep(i,0,vec[l].size()-1) A[i]=vec[l][i]; 66 rep(i,0,vec[mid+1].size()-1) B[i]=vec[mid+1][i]; 67 solve(A,B,lmt); 68 vec[l].clear();vec[mid+1].clear(); 69 rep(i,0,lmt-1) vec[l].push_back(A[i]); 70 } 71 void cdq(int l,int r) 72 { 73 if(l==r) {f[l]=pls(f[l],mul(g[l],l));return ;} 74 int mid=l+r>>1,lmt=r-l+1;cdq(l,mid); 75 int t=l2[lmt]+1;lmt=1<<t; 76 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(t-1)),A[i]=B[i]=0; 77 rep(i,l,mid) A[i-l]=f[i];rep(i,1,r-l) B[i-1]=g[i]; 78 solve(A,B,lmt);rep(i,mid+1,r) f[i]=pls(f[i],A[i-l-1]); 79 cdq(mid+1,r); 80 } 81 int main() 82 { 83 n=read();rep(i,1,n) aa[i]=read();rep(i,2,n<<1) l2[i]=l2[i>>1]+1; 84 rep(i,1,n<<1) pw[i]=q_pow(3,(MOD-1)/i); 85 rep(i,1,n) vec[i].push_back(1),vec[i].push_back(aa[i]); 86 Div(1,n);rep(i,0,n) g[i]=vec[1][i]; 87 rep(i,0,n) if(!(i&1)) g[i]=-g[i]; 88 cdq(0,n);rep(i,1,n) printf("%d\n",f[i]); 89 }