省选模拟19

A. 排队

做两遍 \(lis\) ,分别从前后开始

看看 \(i\) 是否在 \(lis\) 上以及这个权值是否唯一

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lowbit(x) x&-x
#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,ans,a[100010];
int f1[100010],f2[100010],ct[100010];
int BIT1[100010],BIT2[100010];
inline void ins1(int x,int k){for(;x;x-=lowbit(x)) BIT1[x]=max(BIT1[x],k);}
inline int query1(int x){int res=0;for(;x<=n;x+=lowbit(x)) res=max(res,BIT1[x]);return res;}
inline void ins2(int x,int k){for(;x<=n;x+=lowbit(x)) BIT2[x]=max(BIT2[x],k);}
inline int query2(int x){int res=0;for(;x;x-=lowbit(x)) res=max(res,BIT2[x]);return res;}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	n=read();for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++){f1[i]=query2(a[i])+1;ins2(a[i],f1[i]);}
	for(int i=n;i>=1;i--){f2[i]=query1(a[i])+1;ins1(a[i],f2[i]);}
	for(int i=1;i<=n;i++) ans=max(ans,f1[i]);
	for(int i=1;i<=n;i++) if(f1[i]+f2[i]-1==ans) ct[f1[i]]++;
	printf("%d\n",ans);for(int i=1;i<=n;i++) if(f1[i]+f2[i]-1==ans&&ct[f1[i]]==1) printf("%d ",i);
	return 0;
}

B. 树论

\(30\) 暴力算法是设 \(f_{x,i}\) 表示 \(x\) 选 \(i\) 时的方案数 ( \(V\) 为值域范围)

\(f_{x,i}=f_{x,i}\times \sum\limits_{j=1}^Vf_j[gcd(i,j)==1]\)

合并到根的时候对答案贡献

反演一下变成

\(\sum\limits_{j=1}^Vf_j\sum\limits_{d|i,d|j}\mu(d)\)

\(\sum\limits_{d|i}\mu(d)\sum\limits_{d|j}f_j\)

枚举倍数贡献

然后再换一下根就好了

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 1000000007
#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,rt;
int l[60],r[60];
int f[60][50010],g[50010],h[50010],hh[50010],ans[60];
int head[60],ver[110],to[110],tot;
int prime[50010],mu[50010],cnt;
bool is[50010];
int gcd(int x,int y){return (!y)?(x):(gcd(y,x%y));}
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
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;
}
void dfs1(int x,int fa){
	for(int i=l[x];i<=r[x];i++) f[x][i]=1;
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];if(y==fa) continue;dfs1(y,x);
		for(int i=1;i<=50000;i++) g[i]=h[i]=0;
		for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[y];j+=i) md(g[i]+=f[y][j]);
		for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
		for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*h[i]%mod;
	}
}
void dfs2(int x,int fa){
	for(int v1=l[x];v1<=r[x];v1++) (ans[x]+=v1*f[x][v1])%=mod;
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];if(y==fa) continue;
		for(int i=1;i<=50000;i++) g[i]=h[i]=0;
		for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[y];j+=i) md(g[i]+=f[y][j]);
		for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
		for(int i=1;i<=50000;i++) md(h[i]+=mod);
		for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*qpow(h[i],mod-2)%mod,hh[i]=h[i];
		for(int i=1;i<=50000;i++) g[i]=h[i]=0;
		for(int i=1;i<=50000;i++) for(int j=i;j<=50000&&j<=r[x];j+=i) md(g[i]+=f[x][j]);
		for(int i=1;i<=50000;i++) if(g[i]&&mu[i]) for(int j=i;j<=50000;j+=i) (h[j]+=mu[i]*g[i])%=mod;
		for(int i=1;i<=50000;i++) md(h[i]+=mod);
		for(int i=l[y];i<=r[y];i++) f[y][i]=f[y][i]*h[i]%mod;
		for(int i=l[x];i<=r[x];i++) f[x][i]=f[x][i]*hh[i]%mod;
		dfs2(y,x);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	mu[1]=1;
	for(int i=2;i<=50000;i++){
		if(!is[i]) mu[i]=-1,prime[++cnt]=i;
		for(int j=1;j<=cnt&&i*prime[j]<=50000;j++){
			is[i*prime[j]]=1;
			if(i%prime[j]==0) break;
			mu[i*prime[j]]=-mu[i];
		}
	}
	n=read();
	for(int i=1;i<=n;i++) l[i]=read();for(int i=1;i<=n;i++) r[i]=read();
	for(int i=1,x,y;i<n;i++){x=read(),y=read();add(x,y),add(y,x);}
	dfs1(1,0);dfs2(1,0);
	for(int i=1;i<=n;i++) printf("%lld\n",(ans[i]+mod)%mod);
	return 0;
}

C. 麻烦的杂货店

用栈来维护括号序列的匹配

用 \(vector\) 存下所有的合法左端点,每次继承匹配的左端点 \(-1\) 的位置的 \(vector\)

然后根号分治, \(vector\) 大小小于根号的每次暴力用线段树修改

大于的每次二分左端点就行

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#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,m;
int fa[100010],ans[4000010],r[100010];
int stk[100010],p;
struct seg{int mx;}st[100010*4];
vector<int>A,vec[100010];
vector<pair<int,int> >Q[100010];
char str[100010];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void pushup(int rt){st[rt].mx=max(st[lson].mx,st[rson].mx);}
void upd(int rt,int l,int r,int pos,int k){
	if(l==r) return st[rt].mx=max(st[rt].mx,k),void();
	int mid=(l+r)>>1;
	if(pos<=mid) upd(lson,l,mid,pos,k);
	else upd(rson,mid+1,r,pos,k);
	pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return st[rt].mx;
	int mid=(l+r)>>1,res=0;
	if(L<=mid) res=max(res,query(lson,l,mid,L,R));
	if(R>mid) res=max(res,query(rson,mid+1,r,L,R));
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("grocery.in","r",stdin);
	freopen("grocery.out","w",stdout);
	n=read(),m=read();scanf("%s",str+1);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1,l,r;i<=m;i++){l=read(),r=read();Q[r].emplace_back(make_pair(l,i));}
	for(int i=1,j;i<=n;i++){
		if(str[i]=='F') stk[++p]=i;
		else if(p){
			j=stk[p--];fa[i]=getfa(j-1);vec[fa[i]].emplace_back(j);j=fa[i];r[j]=i;
			if(vec[j].size()==2000) A.emplace_back(j);
			else if(vec[j].size()<2000) for(auto L:vec[j]) upd(1,1,n,L,i-L+1);
		}
		for(auto L:Q[i]){
			ans[L.second]=query(1,1,n,L.first,i);
			for(auto Y:A){
				int v=lower_bound(vec[Y].begin(),vec[Y].end(),L.first)-vec[Y].begin();
				if(v!=vec[Y].size()) ans[L.second]=max(ans[L.second],r[Y]-vec[Y][v]+1);
			}
		}
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}
上一篇:排序


下一篇:二分+三分专题与边界处理