「考试」联赛模拟40-45,晚间小测4-9

40.3 MC

删边是不好维护的,考虑离线然后倒序处理,然后就转化成了加边,修改与询问,那么用并查集记录联通块并(map)启发式合并即可
主要代码:

inline void merge(ll u,ll v){
	u=fd(u),v=fd(v);
	if(u==v)return;
	if(mp[u].size()>mp[v].size())swap(u,v);
	f[u]=v; cnt[v]+=cnt[u];
	for(auto i:mp[u])mp[v][i.first]+=i.second;
	mp[u].clear();
	return;	
}

(这是开(c++11)时的做法,否则需要老实写(iterator)

40.4 简单题

怎么这么多“简单题”啊
发现其实就是要一棵最小生成树,考虑(kruskal)的过程,那么加边时如果有边加不进去了,那么以这条边两个端点为端点的链上所有边的答案都对这条边取(min),而这条边的答案就是这条链上的最大值
需要树链的区间修改,查(max)操作,树链剖分即可

41.1 四个质数的和

首先(1e5)以内只有大约一万个质数,但(n^4)枚举肯定不行废话
选出质数的数量只有4个,可以考虑枚举每两个质数的和记录方案数,(4=2+2),那么再枚举所有的两个质数的和,用询问减去它,再查,再相乘即可
因为可以将和大于询问的情况剪掉,所以预处理实际跑不满(O(n^2)),就可以通过了

41.2 匹配最大异或

一个非常优美的性质:把(0)~(2^n-1)(2^{n-1})处分成两部分,那么去掉所有数的二进制最高位,剩下两部分是完全相同的
考虑当前正在决定的一位应该放0还是1,

  • 如果左右相同的位置数相同,那么是可以互换的,这一位可以选0/1有两种
  • 如果左右的取值集合没有相交,那么左边为了最大必须选1,右边为了最大必须选0,这一位只有一种选择方案,那么直接继续分治即可
  • 如果左右取值集合有相交且不是第一种情况,那么一个数肯定无法做到在左右两边都是最大的,这时答案为0
因为自己也看不懂自己在说些什么所以放了代码:


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define S (1<<16)
#define mod 1000000007

ll n,m;
ll p[S],vis[S];

inline ll sol(ll l,ll r){
	if(l==r)return 1;
	ll flag=1,m=(l+r)>>1;
	for(int i=l;i<=m;i++)if(p[i]!=p[m+i-l+1])flag=0;
	if(flag)return 1ll*sol(l,m)*2%mod;
	memset(vis,0,sizeof vis);
	for(int i=l;i<=m;i++)vis[p[i]]=1;
	for(int i=m+1;i<=r;i++)if(vis[p[i]])return 0;
	return 1ll*sol(l,m)*sol(m+1,r)%mod;
}

inline ll read(){
	ll f=0,s=0; char c=getchar();
	while(c>'9'||c<'0')f=(c=='-'),c=getchar();
	while(c>='0'&&c<='9')s=(s<<3)+(s<<1)+(c^'0'),c=getchar();
	return f?-s:s;
}

int main(){
	freopen("match.in","r",stdin);
	freopen("match.out","w",stdout);
	m=read(); n=read();
	for(int i=0;i<(1<<m);i++){
		p[i]=read();
	}
	printf("%d",sol(0,(1<<m)-1));
	return 0;
}

41.3 染色相邻的边

发现一条被修改过的边为黑色的充要条件即为它两个端点最后被修改过的时间不同
因为这样判断是否被修改过很麻烦,又因为开始是全为黑色,所以开始时可以直接给每一个点赋不同的时间戳
那么要看有多少黑边就是看有多少两个端点时间戳不同的边,也就是看树链上有多少颜色(时间戳)段再-1
就转化成了[SDOI2011]染色
调树剖真有意思

42.4 58号元素

首先可以单调栈处理出所有位置的(next),那么可以建出一棵树,如果加入一个数,那么它的子树里答案都+1,删除时即为-1
那么在新树上处理出dfs序就可以用线段树维护了

43.1 糖果机器

首先如果一个机器人可以从(i)(j),有(t_j-t_igeq |s_j-s_i|)
即:

[egin{cases} t_j-t_igeq s_j-s_i\ t_j-t_igeq s_i-s_j end{cases}]

可转化为

[egin{cases} t_j-s_jgeq t_i-s_i\ t_j+s_jgeq t_i+s_i end{cases}]

换元可得:

[egin{cases} X_jgeq X_i\ Y_jgeq Y_i end{cases}]

就是一个二维偏序,其实和导弹拦截是同理的,需要求一个最长反链,那么按一维排序后树状数组即可
关于方案:每个位置只要贪心选取上一个能转移的即可

原文地址:https://www.cnblogs.com/zzzuozhe-gjy/p/14075378.html