2022.02.10 模拟赛

Tree

Step 1

设当 \(k=i\) 时,一共需要 \(ans_i\) 条链。当 \(k=i+1\) 时,\(ans_{i+1}<=ans_i\) 。情况最差就是把 \(k=i\) 时的覆盖方式再覆盖一遍。

Step 2

对于每个叶子节点,无论怎么选,它们一定会被选到链上(废话,每个点都会被选!),不过叶子们更优。这就是个贪心的小方法。再仔细一想,对于每个点,我们只需要把这些点的儿子们计算出来需要多少条链覆盖,然后从中选择一个剩余链数最长的就行。

计算剩余链数可以用dfs序,完美地把一个递归变成一个for循环,老方便了。

Step 3

这是个有根树,所以说可爱的链子最长也就是最深的层数,接下来的 \(dep\) 可以等同于链长。

设最深的层数为 \(maxndep\) 。因为是多次询问,而且 \(q\) 贼大,干脆优选打这一摊询问处理完算了。

用类似于分治的方法:

1.对 \(dep\) 分治,每一块的 \(depl\)\(depr\) 都会在 \(ans_{depl}==ans_{depr}\) 时更新这个区间

2.在一块 \(depl\)\(depr\) 之间(链长递增),\(ans\) 也不上升,每次查询出 \(ans_{dep_{mid}}\)\(ans_{dep_{mid+1}}\) ,可以确定下一个分治区间 \(ans\) 的取值范围,为步骤1做铺垫

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm> 
#include<cstring>
#include<bits/stdc++.h>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define R register
const int N=1e5+10;
int n,m,cnt,head[N],vis[N],dep[N],fa[N];
int maxndep,ind,dfsx[N],ans[N],f[N];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void dfs(int x,int fai){
	fa[x]=fai;
	dep[x]=dep[fai]+1;
	dfsx[++ind]=x;
	maxndep=max(maxndep,dep[x]);
	for(R int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fai)continue;
		dfs(v,x);
	}
}
inline int query(int k){
	int len=k,now=0;
	memset(f,0,sizeof(f));
	for(R int i=n;i>=1;i--){
		if(f[dfsx[i]]==0)f[dfsx[i]]=len,++now;
		f[fa[dfsx[i]]]=max(f[fa[dfsx[i]]],f[dfsx[i]]-1);
	}
	return now;
}
inline void final(int l1,int r1,int l2,int r2){
	if(l2==r2){
		for(R int i=l1;i<=r1;i++)ans[i]=l2;
		return ;
	}
	int mid=(l1+r1)>>1;
	int midl=query(mid),midr=query(mid+1);
	final(l1,mid,l2,midl);final(mid+1,r1,midr,r2);
}

signed main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n=read();
	for(R int i=1;i<n;i++){
		int u,v;
		u=read();v=read();
		add(u,v);add(v,u);
	}
	dfs(1,0);
	//cout<<"dep "<<endl;
	//for(R int i=1;i<=n;i++)cout<<dep[i]<<" ";cout<<endl;
	final(1,maxndep,query(1),query(maxndep));
	//cout<<"ans "<<endl;
	//for(R int i=1;i<=maxndep;i++)cout<<ans[i]<<" ";cout<<endl;
	m=read();
	for(R int i=1;i<=m;i++){
		int x=read();
		x=min(x,maxndep);
		cout<<ans[x]<<endl;
	}
	return 0;
}
/*
7
1 2
3 1
3 4
5 4
4 7
6 2
3
1 
2
3
ans 7 4 3
*/

Count

Step 1

我是废物,我不会,我思索思索。

Sort

Step 1

手动计算之后,发现一个小规律:
对于数字 \(a\)\(b\) ,且 \(a<b\) ,会产生两种结果: \(a,b\)\(b,a\)

当顺序是 \(a,b\) 时,接下来 \(a\)\(b\) 是两个数;

当顺序是 \(b,a\) 时,接下来 \(b,a\) 当成一个数或者 \(a=b+0.5\)

所以 \(a=a||b+0.5\)\(b=b\)

Step 2

题目的操作2可以转化为查询 \(num[x]\) 排序后有 \(y-1\) 个数比它小的排列有几种。

看到“比它小”,看到“\(y-1\)”,上来就是一个树状数组,哦不对,是俩:一个记录顺序为 \(a,b\) 的,称为 \(minn\) ;另一个记录顺序为 \(b,a\) ,称之为 \(maxn\)

因为有 \(b+0.5\) ,这种骚气的数字,所以 \(a\) 的值与 \(b\) 的值统统乘2。

对于操作2:

\(minnans\) 是在 \(minn\) 中查询到的比 \(num[x]\) 小的数字个数,\(maxnans\) 则是在 \(maxn\) 中查询到的比 \(num[x]\) 的数字个数,则 \(maxnans<=minnans\) (我随便写的,就是这个意思)。

Case 1 第 \(x\) 项是较小值

如果 \(minnans>=y-1\) 并且 \(maxnans<y\) ,说明肯定有某些情况存在有 \(y-1\) 个数比 \(num[x]\) 小(看看这两个比较就知道),然后上组合数学:

\[ans=\frac{(minnans-maxnans)!}{(minnans-(y-1))!*((y-1)-maxnans)!} \]

Case 2 第 \(x\) 项是较大值

前面跟 \(Case 1\) 一样,懒得复制了,只不过如果第 \(x\) 项较小值小于较大值而不是等于,本身就是较大值了, \(minnans=minnans-1\)

实际上这两种情况我还是有点儿小懵逼,毕竟是真的就是半猜的,尤其是 \(Case 2\) 的减一,笔算之后才发现错了,我枯了/欲哭无泪脸。

Step 3

操作1就是交换两个值,然后修改。

Step 4

记得预处理一下乘法逆元和阶乘,方便算 \(ans\)

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm> 
#include<cstring>
#include<bits/stdc++.h>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
#define R register
const int N=7e4;
const int M=N*2;
const int mod=1e9+7;
int n,m,num[N],a[N],b[N];//a:minn b:maxn
int fac[N],inv[N],powi[N];
struct node{
	int val[M];
	inline void init(){
		memset(val,0,sizeof(val));
	}
	inline int lowbit(int x){
		return x&(-x);
	}
	inline void add(int x,int k){
		if(!x)return ;
		for(R int i=x;i<=n*2+1;i+=lowbit(i))val[i]+=k;
	}
	inline int query(int x){
		int ans=0;
		for(R int i=x;i;i-=lowbit(i))ans+=val[i];
		return ans;
	}
};
node maxn,minn;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void change(int x){
	minn.add(a[x],-1);minn.add(a[x+1],-1);
	maxn.add(b[x],-1);maxn.add(b[x+1],-1);
	//cout<<"Case 1"<<endl;
	if(num[x]<num[x+1])
	a[x]=2*num[x],b[x]=2*num[x+1]+1,a[x+1]=b[x+1]=2*num[x+1];
	else a[x]=b[x]=2*num[x],a[x+1]=2*num[x+1],b[x+1]=2*num[x]+1;
	//cout<<"Case 2"<<endl;
	minn.add(a[x],1);minn.add(a[x+1],1);
	maxn.add(b[x],1);maxn.add(b[x+1],1);
	//cout<<"Case 3"<<endl;
}
inline void init(){
	fac[0]=fac[1]=1;
	for(R int i=2;i<=n;i++)fac[i]=fac[i-1]*i%mod;
	//cout<<"fac "<<endl;
	//for(R int i=1;i<=n;i++)cout<<fac[i]<<" ";cout<<endl;
	inv[0]=inv[1]=1;
	for(R int i=2;i<=n;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
	//cout<<"inv "<<endl;
	//for(R int i=1;i<=n;i++)cout<<inv[i]<<" ";cout<<endl;
	for(R int i=2;i<=n;i++)inv[i]=inv[i]*inv[i-1]%mod;
	//cout<<"inv of fac "<<endl;
	//for(R int i=1;i<=n;i++)cout<<inv[i]<<" ";cout<<endl;
	powi[0]=1;
	for(R int i=1;i<=n;i++)powi[i]=powi[i-1]*inv[2]%mod;
	//cout<<"powi "<<endl;
	//for(R int i=1;i<=n;i++)cout<<powi[i]<<" ";cout<<endl;
}
inline void right(int x){
	if(x&1)change(x);else change(x-1);
}
inline int calc(int x,int y){
	//x!/{(x-y)!y!}
	int fin=fac[x]*inv[x-y]%mod*inv[y]%mod;
	return fin;
}

signed main(){
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	n=read();init();
	for(int i=1;i<=n;i++)num[i]=read();
	if(n==1){
		m=read();
		for(R int i=1;i<=m;i++){
			int op,x,y;
			op=read();x=read();y=read();
			puts("1");
		}
		return 0;
	}
	maxn.init();minn.init();
	//cout<<"change "<<endl;
	for(R int i=1;i<=n;i+=2)change(i);//,cout<<i<<" ";cout<<endl;
	m=read();
	for(R int i=1;i<=m;i++){
		int op,x,y;
		op=read();x=read();y=read();
		if(op==1){
			swap(num[x],num[y]);
			right(x);right(y);
		}else if(op==2){
			//a[x]:the aim
			int minnans=minn.query(a[x]-1);
			int maxnans=maxn.query(a[x]-1);
			int fin=0;
			if(minnans>=y-1&&maxnans<y)
			fin=(fin+calc(minnans-maxnans,y-1-maxnans)*powi[minnans-maxnans+1]%mod)%mod;
			//cout<<minnans<<" "<<maxnans<<endl;
			//cout<<fin<<endl;
			minnans=minn.query(b[x]-1);
			maxnans=maxn.query(b[x]-1);
			if(b[x]>a[x])--minnans;
			if(minnans>=y-1&&maxnans<y)
			fin=(fin+calc(minnans-maxnans,y-1-maxnans)*powi[minnans-maxnans+1]%mod)%mod;
			//cout<<minnans<<" "<<maxnans<<endl;
			//cout<<fin<<endl;
			cout<<fin<<endl;
		}
	}
	return 0;
}
/*
4
1 4 2 3
3
2 4 2
1 1 3
2 3 1
ans 
500000004
500000004
*/
 posted on 2022-02-10 21:41  eleveni  阅读(44)  评论(0)    收藏  举报