2019/11/01 校内模拟

T1 曾经排队

挺水的。

  • 询问 1 1 1:所有 c i c_i ci 都是 a a a 的倍数。记一下所有 c i c_i ci 的最大公约数即可。
  • 询问 2 2 2:对于所有的 c i c_i ci 都有 a ≤ ⌈ c i a ⌉ a\le\lceil\frac{c_i}{a}\rceil aaci。记一下最小的 c i c_i ci 判一下即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c=gc();T x=0,f=1;
		while(!isdigit(c))  f^=(c=='-'),c=gc();
		while( isdigit(c))  x=((x+(x<<2))<<1)+(c^48),c=gc();
		return f?x:-x;
	}
	inline int gi()  {return Read<int>();}
	inline ll  gl()  {return Read<ll >();}
}
using IO::gi;
using IO::gl;
const int N=7e5+5;
int n,q,type;
ll val,Gcd=0,mn=1e18;
ll gcd(ll x,ll y)  {return y?gcd(y,x%y):x;}
void Min(ll &x,ll y)  {if(x>y)x=y;}
int main(){
	n=gi();
	for(int i=1;i<=n;++i){
		ll x=gl();
		Gcd=gcd(Gcd,x),Min(mn,x);
	}
	q=gi();
	while(q--){
		val=gl(),type=gi();
		if(type==1)  puts(Gcd%val?"No":"Yes");
		else{
			if(val>=1e9)  puts("No");
			else  puts(mn<=val*val?"No":"Yes");
		}
	}
	return 0;
}

T2 元素世界

这就是一道模拟题。

考虑两个串相似的条件是,字母出现次数 的个数相同。

例如 abbccbecbe,出现两次的字母都有 2 2 2 个,出现一次的字母都只有 1 1 1 个,因此它们相似。

于是根据这个模拟就可以了。

时间复杂度 O ( T n q × 26 ) O(Tnq\times26) O(Tnq×26)

#include<bits/stdc++.h>
using namespace std;
const int N=2005;
int T,n,q,l,r,len;
int cnt1[26],cnt2[26],num1[N],num2[N];
char S[N];
vector<int>p;
bool check(){
	for(int i=0;i<p.size();++i)
		if(num1[p[i]]^num2[p[i]])  return false;
	return true;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%s",&n,&q,S+1);
		while(q--){
			scanf("%d%d",&l,&r),p.clear(),len=r-l+1;
			for(int i=l;i<=r;++i)  cnt1[S[i]-'a']++,cnt2[S[i-l+1]-'a']++;
			for(int i=0;i<26;++i)  num1[cnt1[i]]++,num2[cnt2[i]]++;
			for(int i=0;i<26;++i)  if(cnt1[i])  p.push_back(cnt1[i]);
			int ans=check();
			for(int i=r-l+2;i<=n;++i){
				int &L=cnt2[S[i-len]-'a'],&R=cnt2[S[i]-'a'];
				num2[L--]--,num2[L]++,num2[R++]--,num2[R]++,ans+=check();
			}
			printf("%d\n",ans);
			for(int i=0;i<26;++i)
				num1[cnt1[i]]=num2[cnt2[i]]=0,cnt1[i]=0,cnt2[i]=0;
		}
	}
	return 0;
}

T3 层层回忆

首先不难发现的是每个点的 f f f 值是子树的 a i a_i ai 和。

由于 a i a_i ai 是正整数,可以发现,父亲节点的 f f f 值严格大于子树中任意节点的 f f f

所以肯定不能往子树走,而往父亲走的话已经有了最大值的限制,我们只需保证当前点不是路径的最小值即可

那么问题就转换成了,对于点 x x x,查询 [ 1 , i n x − 1 ] [1,\mathrm{in}_x-1] [1,inx1] 以及 [ o u t x + 1 , n ] [\mathrm{out}_x+1,n] [outx+1,n] f f f < f x <f_x <fx 的或和。

可以对 f f f 从小到大排序,按照顺序加到权值线段树上,然后每个点查一查即可。

注意一下 f f f 相等的 “ “ 去重 ” ”

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c=gc();T x=0,f=1;
		while(!isdigit(c))  f^=(c=='-'),c=gc();
		while( isdigit(c))  x=((x+(x<<2))<<1)+(c^48),c=gc();
		return f?x:-x;
	}
	inline int gi()  {return Read<int>();}
}
using IO::gi;
const int N=5e5+5;
int n,rt,mx;
int t,first[N],v[N<<1],nxt[N<<1];
void add(int x,int y){
	nxt[++t]=first[x],first[x]=t,v[t]=y;
}
int tot,f[N],in[N],out[N],ans[N];
void dfs(int x,int fa){
	in[x]=++tot;
	for(int i=first[x];i;i=nxt[i]){
		int to=v[i];
		if(to==fa)  continue;
		dfs(to,x),f[x]+=f[to];
	}
	out[x]=tot;
}
namespace SGT{
	int Or[N<<2];
	#define mid ((l+r)>>1)
	void Modify(int root,int l,int r,int pos,int val){
		if(l==r)  {Or[root]|=val;return;}
		if(pos<=mid)  Modify(root<<1,l,mid,pos,val);
		else  Modify(root<<1|1,mid+1,r,pos,val);
		Or[root]=Or[root<<1]|Or[root<<1|1];
	}
	int Query(int root,int l,int r,int x,int y){
		if(l>=x&&r<=y)  return Or[root];
		if(y<=mid)  return Query(root<<1,l,mid,x,y);
		if(x> mid)  return Query(root<<1|1,mid+1,r,x,y);
		return Query(root<<1,l,mid,x,y)|Query(root<<1|1,mid+1,r,x,y);
	}
	#undef mid
}
vector<int>Sort[3000005];
void Max(int &x,int y)  {if(x<y)x=y;}
int main(){
	n=gi(),rt=gi();
	for(int i=1,x,y;i<n;++i){
		x=gi(),y=gi(),add(x,y),add(y,x);
	}
	for(int i=1;i<=n;++i)  f[i]=gi();
	dfs(rt,0);
	for(int i=1;i<=n;++i)  Sort[f[i]].push_back(i),Max(mx,f[i]);
	for(int i=1;i<=mx;++i){
		for(int j=0;j<Sort[i].size();++j){
			int x=Sort[i][j];
			if(in[x]>1)  ans[x]|=SGT::Query(1,1,n,1,in[x]-1);
			if(out[x]<n)  ans[x]|=SGT::Query(1,1,n,out[x]+1,n);
		}
		for(int j=0;j<Sort[i].size();++j){
			int x=Sort[i][j];
			SGT::Modify(1,1,n,in[x],f[x]);
		}
	}
	for(int i=1;i<=n;++i)  printf("%d ",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值