省选模拟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<bits/stdc++.h>
#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<bits/stdc++.h>
//#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<bits/stdc++.h>
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];
vector<int>L[100010];
inline bool cmp(int x,int y){return dep[x]<dep[y];}
void dfs1(int x){
siz[x]=1,son[x]=0;
int maxson=-1;
for(int i=0;i<=1;i++){
int y=tr[x][i];if(!y) continue;
dfs1(y);siz[x]+=siz[y];
if(siz[y]>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];
}