省选模拟7


A. 高中数列题

\(p_i=\left \lfloor \frac{i+b}{c} \right \rfloor\)

\(a_n\) 展开得到 \(a_n=a+\sum\limits_{i=1}^nf(i)*a_{p_i}\)

考虑求 \(\sum\limits_{i=1}^nf(i)*a_{p_i}\)

再展开一步变成 \(\sum\limits_{i=1}^nf(i)(\sum\limits_{j=1}^{p_i}f(j)a_{p_j}+a)\)

\(a*\sum\limits_{i=1}^nf(i)+\sum\limits_{i=1}^nf(i)\sum\limits_{j=1}^{p_i}f(j)a_{p_j}\)

后面的部分把 \(j\) 提前变成

\(a*\sum\limits_{i=1}^nf(i)+\sum\limits_{j=1}^{p_n}f(j)a_{p_j}\sum\limits_{i=q_j}^nf(i)\)

\(q_j\) 为最小的满足 \(p_x=j\) 的数

\(sf(n)=\sum\limits_{i=1}^n\)

那么就变成了 \(a*sf(n)+\sum\limits_{j=1}^{p_n}f(j)a_{p_j}(sf(n)-sf(q_j-1))\)

然后把 \(f(j)(sf(n)-sf(q_j-1))\) 看成 \(g(j)\) 就能递归处理了

每层都值都能用拉格朗日插值插出来

Code
#include
#define int long long
#define rint signed
#define mod 1004535809
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,b,c,m,ans,K;
int a[110],v[110],t[2010];
int fac[2010],inv[2010];
inline void md(int &x){x=(x>=mod)?x-mod:x;}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline int f(int x){
	int res=0;
	for(int i=0,base=1;i<=m;i++,base=1ll*base*x%mod) md(res=res+1ll*v[i]*base%mod);
	return res;
}
namespace LL{
	inline int lagrange1(int n,int *x,int *y,int xi){
		int res=0;xi%=mod;
		for(int i=0,s1,s2;i<=n;i++){
			s1=s2=1;
			for(int j=0;j<=n;j++) if(i!=j) s1=s1*(xi-x[j]+mod)%mod,s2=s2*(x[i]-x[j]+mod)%mod;
			md(res=res+y[i]*s1%mod*qpow(s2,mod-2)%mod);
		}
		return res;
	}
	int s1[2010],s2[2010];
	inline int lagrange(int n,int *x,int *y,int xi){
		int ans=0;xi%=mod;
		s1[0]=(xi-x[0]+mod)%mod,s2[n+1]=1;
		for(int i=1;i<=n;i++) s1[i]=s1[i-1]*(xi-x[i]+mod)%mod;
		for(int i=n;~i;i--) s2[i]=s2[i+1]*(xi-x[i]+mod)%mod;
		for(int i=0;i<=n;i++) ans=(ans+y[i]*(i==0?1:s1[i-1])%mod*s2[i+1]%mod*inv[i]%mod*(((n-i)&1)?-1:1)*inv[n-i]%mod+mod)%mod;
		return ans;
	}
	int x[2010],y[2010],s[2010];
	inline int f(int n,int k){return lagrange(k,x,y,n);}
	inline void pre(int k){
		for(int i=0;i<=k+1;i++) s[i]=lagrange(k,x,y,i);
		for(int i=1;i<=k+1;i++) md(s[i]+=s[i-1]);
	}
	inline int sumf(int n,int k){
		return (lagrange(k+1,x,s,n)-s[0]+mod)%mod;
	}
}
inline int p(int x){return (x+b)/c;}
inline int q(int x){return x*c-b;}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	fac[0]=inv[0]=1;for(int i=1;i<=2000;i++) fac[i]=fac[i-1]*i%mod,inv[i]=inv[i-1]*qpow(i,mod-2)%mod;
	n=read(),a[0]=read(),b=read(),c=read(),m=read();K=m;
	for(int i=0;i<=m;i++) v[i]=read();
	for(int i=0;i<=2000;i++) LL::x[i]=i;
	for(int i=0;i<=K;i++) LL::y[i]=f(i);
	for(int i=1;i<=50;i++) a[i]=(a[i-1]+f(i)*a[p(i)])%mod;
	ans=a[0];
	while(1){
		if(!n) break;LL::pre(K);
		(ans+=a[0]*LL::sumf(n,K))%=mod;K+=m+1;
		for(int i=0;i<=K;i++) t[i]=f(i)*(LL::sumf(n,K-m-1)-LL::sumf(q(i)-1,K-m-1)+mod)%mod;
		for(int i=0;i<=K;i++) LL::y[i]=t[i];n=p(n);
	}
	printf("%lld\n",ans);
	return 0;
}

B. 机动车限行

分别把 \(2,3\) 去掉然后和 \(1\) 去做并查集合并

然后把不含 \(1\) 的联通块都去掉,用剩下的建二分图跑最大匹配

左边是 \(1,3\) 的块,右边是 \(1,2\) 的块

然后用点数减去最大流就行,构造方案的话,有流量的必选,其他的随便选

剩下的两个同理

Code
#include
//#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,S,T,cur,cnt;
int a[1000010];
int dis[1000010],q[1000010],h,t;
int head[1000010],HD[1000010],from[1000010],ver[1000010],edge[1000010],to[1000010],id[1000010],tot;
struct DSU{
	int fa[1000010];
	bool vis[1000010];
	int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
	inline void merge(int x,int y){
		x=getfa(fa[x]),y=getfa(fa[y]);if(x==y) return ;
		if(vis[x]) swap(x,y);
		fa[x]=y;vis[y]|=vis[x];
	}
	inline void init(int opt){for(int i=1;i<=n;i++) fa[i]=i,vis[i]=(a[i]==opt);}
}s1,s2;
struct E{int x,y;}e[1000010];
inline void clear(){memset(head,0,sizeof(head));tot=1;cnt=0;}
inline void add(int x,int y,int z,int w){
	ver[++tot]=y;from[tot]=x;edge[tot]=z;id[tot]=0;to[tot]=head[x];head[x]=tot;
	ver[++tot]=x;from[tot]=y;edge[tot]=0;id[tot]=w;to[tot]=head[y];head[y]=tot;
}
inline bool bfs(){
	for(int i=1;i<=T;i++) dis[i]=inf;
	dis[S]=0,q[h=t=1]=S;
	memcpy(head,HD,sizeof(head));
	while(h<=t){
		int x=q[h++];
		for(int i=head[x];i;i=to[i]) if(edge[i]){
			int y=ver[i];
			if(dis[y]>dis[x]+1){
				dis[y]=dis[x]+1;
				q[++t]=y;
			}
		}
		if(x==T) return true;
	}
	return false;
}
int dfs(int x,int in){
	if(x==T) return in;
	int res=in,go;
	for(int i=head[x];i;head[x]=i=to[i]) if(edge[i]){
		int y=ver[i];
		if(dis[y]==dis[x]+1){
			go=dfs(y,min(res,edge[i]));
			if(go) res-=go,edge[i]-=go,edge[i^1]+=go;
			else dis[y]=0;
		}
		if(!res) break;
	}
	return in-res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("restriction.in","r",stdin);
	freopen("restriction.out","w",stdout);
	n=read(),m=read();S=2*n+1;T=S+1;
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read();
	clear();
	s1.init(1);for(int i=1;i<=m;i++){if(a[e[i].x]==2||a[e[i].y]==2) continue;s1.merge(e[i].x,e[i].y);}
	s2.init(1);for(int i=1;i<=m;i++){if(a[e[i].x]==3||a[e[i].y]==3) continue;s2.merge(e[i].x,e[i].y);}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i){if(!s1.vis[i]) continue;cnt++;add(S,i,1,0);}
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i){if(!s2.vis[i]) continue;cnt++;add(i+n,T,1,0);}
	for(int i=1,x,y;i<=n;i++){
		x=s1.getfa(i);y=s2.getfa(i);
		if(!s1.vis[x]||!s2.vis[y]) continue;
		add(x,y+n,1,i);
	}
	memcpy(HD,head,sizeof(head));
	while(bfs()) cnt-=dfs(S,inf);
	printf("%d ",cnt);
	for(int i=3,x,y;i<=tot;i+=2) if(edge[i]){
		x=from[i],y=ver[i];
		s1.vis[x]=0,s2.vis[y-n]=0;
		if(id[i]) printf("%d ",id[i]);
	}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i&&s1.vis[i]) printf("%d ",i);
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i&&s2.vis[i]) printf("%d ",i);puts("");
	
	clear();
	s1.init(2);for(int i=1;i<=m;i++){if(a[e[i].x]==1||a[e[i].y]==1) continue;s1.merge(e[i].x,e[i].y);}
	s2.init(2);for(int i=1;i<=m;i++){if(a[e[i].x]==3||a[e[i].y]==3) continue;s2.merge(e[i].x,e[i].y);}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i){if(!s1.vis[i]) continue;cnt++;add(S,i,1,0);}
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i){if(!s2.vis[i]) continue;cnt++;add(i+n,T,1,0);}
	for(int i=1,x,y;i<=n;i++){
		x=s1.getfa(i);y=s2.getfa(i);
		if(!s1.vis[x]||!s2.vis[y]) continue;
		add(x,y+n,1,i);
	}
	memcpy(HD,head,sizeof(head));
	while(bfs()) cnt-=dfs(S,inf);
	printf("%d ",cnt);
	for(int i=3,x,y;i<=tot;i+=2) if(edge[i]){
		x=from[i],y=ver[i];
		s1.vis[x]=0,s2.vis[y-n]=0;
		if(id[i]) printf("%d ",id[i]);
	}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i&&s1.vis[i]) printf("%d ",i);
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i&&s2.vis[i]) printf("%d ",i);puts("");

	clear();
	s1.init(3);for(int i=1;i<=m;i++){if(a[e[i].x]==2||a[e[i].y]==2) continue;s1.merge(e[i].x,e[i].y);}
	s2.init(3);for(int i=1;i<=m;i++){if(a[e[i].x]==1||a[e[i].y]==1) continue;s2.merge(e[i].x,e[i].y);}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i){if(!s1.vis[i]) continue;cnt++;add(S,i,1,0);}
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i){if(!s2.vis[i]) continue;cnt++;add(i+n,T,1,0);}
	for(int i=1,x,y;i<=n;i++){
		x=s1.getfa(i);y=s2.getfa(i);
		if(!s1.vis[x]||!s2.vis[y]) continue;
		add(x,y+n,1,i);
	}
	memcpy(HD,head,sizeof(head));
	while(bfs()) cnt-=dfs(S,inf);
	printf("%d ",cnt);
	for(int i=3,x,y;i<=tot;i+=2) if(edge[i]){
		x=from[i],y=ver[i];
		s1.vis[x]=0,s2.vis[y-n]=0;
		if(id[i]) printf("%d ",id[i]);
	}
	for(int i=1;i<=n;i++) if(s1.getfa(i)==i&&s1.vis[i]) printf("%d ",i);
	for(int i=1;i<=n;i++) if(s2.getfa(i)==i&&s2.vis[i]) printf("%d ",i);puts("");
	return 0;
}

C. 城市绿化

可以树链剖分,从浅到深处理

每次选重链的链底和当前点求 \(lca\) 然后判断是否为父亲

然后走重儿子相反的儿子重复这个方法,直到找到父亲

然后每插入 \(\sqrt n\) 个数就重构一下树剖

Code
#include "green.h"
#include
using namespace std;
int visit(int,int);
int n,blo,a[100010];
int dep[100010],FF[100010],siz[100010],son[100010],top[100010];
int tr[100010][2];
vectorL[100010];
inline bool cmp(int x,int y){return dep[x]maxson) son[x]=y,maxson=siz[y];
	}
}
void dfs2(int x,int topf){
	top[x]=topf;L[topf].emplace_back(x);
	if(!son[x]) return ;
	dfs2(son[x],topf);
	for(int i=0;i<=1;i++){
		int y=tr[x][i];
		if(!y||son[x]==y) continue;
		dfs2(y,y);
	}
}
inline void rebuild(){
	for(int i=1;i<=n;i++) L[i].clear();
	dfs1(1);dfs2(1,1);
}
inline int getfa(int x){
	int rt=1;
	while(1){
		int d=visit(x,L[rt].back());
		int lca,deplca;
		deplca=((dep[x]+dep[L[rt].back()])-d)/2;
		lca=L[rt][deplca-dep[rt]];
		//printf("L[rt].back() : %d\n",L[rt].back());
		//printf("rt : %d lca : %d deplca : %d\n",rt,lca,deplca);
		if(dep[lca]+1==dep[x]) return lca;
		rt=tr[lca][tr[lca][0]==son[lca]];
		//printf("rt : %d\n",rt);
	}
	return 1;
}
void print(int x){
	if(!x) return ;
	printf("x : %d\n",x);
	print(tr[x][0]);
	print(tr[x][1]);
}
inline void ins(int x){
	if(!tr[FF[x]][0]) tr[FF[x]][0]=x,son[FF[x]]=x,top[x]=top[FF[x]];
	else tr[FF[x]][1]=x,top[x]=x;
	L[top[x]].emplace_back(x);
}
void findtree(int n,int m,int *p){
	::n=n;for(int i=2;i<=n;i++) dep[i]=visit(1,i);
	blo=sqrt(n)+1;top[1]=1;L[top[1]].emplace_back(1);
	for(int i=1;i<=n;i++) a[i]=i;sort(a+1,a+1+n,cmp);
	for(int i=2,x;i<=n;i++){
		x=a[i];
		//printf("sx : %d\n",x);fflush(stdout);
		FF[x]=getfa(x);ins(x);
		if(i%blo==0) rebuild();
		//print(1);fflush(stdout);
	}
	for(int i=2;i<=n;i++) p[i]=FF[i];
}