2020.4.5学军信友队趣味网络邀请赛总结

题目点此
T1由于是找规律题,不好讲述且讲述意义不大,所以就不说了。

T2

给你一棵带点权的树,你要选择一对点 ( x , y ) (x,y) (x,y) a x > a y a_x>a_y ax>ay,使得贡献 a x ∗ d i s t ( x , y ) a_x*dist(x,y) axdist(x,y)最大。
求最大贡献。

第一眼感觉这是一道一定能切的题目。
第二眼想到可以 L C T LCT LCT做,但放在第二题肯定不是 L C T LCT LCT
第三眼想到树剖,推了推后搞出了一个类似于动态 D P DP DP的方法。
打了一半感觉常数可能有点大,然后想到点分治。
点分治一开始打个带set的,后来感觉常数太大,换了另一种打法:
将子树依次加进去,用线段树维护权值小于等于多少时的最大值,子树加进去的时候计算贡献;正着做一遍,反着做一遍。
交上去TLE,改成树状数组AC。
此时比赛开始了约80min。

领会到正解之后我意识到我sb了……
题目变一下就是 m a x ( a x , a y ) ∗ d i s t ( x , y ) = m a x ( a x ∗ d i s t ( x , y ) , a y ∗ d i s t ( x , y ) ) max(a_x,a_y)*dist(x,y)=max(a_x*dist(x,y),a_y*dist(x,y)) max(ax,ay)dist(x,y)=max(axdist(x,y),aydist(x,y))
所以就是对于每个点找它的最远点的问题……
找出直径,某个点的最远点肯定是两个直径端点之一。


T3

有个数组 a 1.. n a_{1..n} a1..n,一开始有个在 [ 1 , a n ] [1,a_n] [1,an](整数)中等概率随机的值 x x x(你不知道它具体是多少)。
可以随时查询 x x x的状态, x x x的状态为 i i i即为 x ∈ [ a i − 1 + 1 , a i ] x\in [a_{i-1}+1,a_i] x[ai1+1,ai]
然后有若干种操作,每种操作的使用次数和使用顺序是任意的,记为 ( v j , w j ) (v_j,w_j) (vj,wj)
表示花 v j v_j vj的代价可以使 x x x w j w_j wj
问使 x x x达到状态 1 1 1的最小步数的期望,结果乘 a n a_n an

这个题意可能不太好理解。点明这一点可能就懂了:由于 x x x是随机的,所以只能确定 x x x在某个区间中而不知道具体的值。所谓“状态”的作用就是进一步区分 x x x,以影响以后的决策。
理解了题意之后就会有个很显然的DP,
d p i , j dp_{i,j} dpi,j表示区间为 [ i , j ] [i,j] [i,j]时的答案,转移方程显然。
接下来脑子一动出现了一个思路,能不能只计算 i i i j j j在某个状态的边界时的答案呢?
于是开打……
调试的时候发现忽略了区间 [ i , j ] [i,j] [i,j]左移之后没有被分割的情况,这时候离结束还没有十分钟……
于是急了,想改回前面的暴力,可惜时间不够。

其实我前面的思路都是没有问题的,现在问题是如何处理被分割的情况。
正解的骚做法就是强制区间在左移后被分割(或者整个区间移到状态 1 1 1)。
显然,一个区间内的数想要变成状态 1 1 1,必须要经历这样的过程。
但是如何保证可以做得到,并且最优呢?
先对各种操作搞一遍完全背包,那么就相当于有 a n a_n an种操作,并且保证是最优的。

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define N 2010
#define ll long long
int n,m;
int a[N];
int pre[N],suc[N];
struct Op{
	int v,w;
} o[N];
ll v[N];
ll f[N],g[N],s[N];
ll calc(int,int);
ll getg(int x){return g[x]!=-1?g[x]:g[x]=calc(a[pre[x]]+1,x);}
ll getf(int x){return f[x]!=-1?f[x]:f[x]=calc(x,a[suc[x]]);}
ll calc(int L,int R){
	ll res=0x7f7f7f7f7f7f7f7f;
	for (int i=1;i<=a[n] && L-i>0;++i)
		if (v[i]!=0x7f7f7f7f7f7f7f7f && (suc[L-i]!=suc[R-i] || R-i<=a[1])){
			int l=L-i,r=R-i;
			ll tmp=v[i]*(r-l+1)+getf(l)+getg(r);
			l=a[suc[l]]+1,r=a[pre[r]];
			if (l<=r)
				tmp+=s[suc[r]]-s[suc[l]-1];
			res=min(res,tmp);
		}
	return res;
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%d%d",&n,&m);
		memset(pre,0,sizeof pre);
		memset(suc,0,sizeof suc);
		for (int i=1;i<=n;++i)
			scanf("%d",&a[i]),pre[a[i]+1]=suc[a[i]]=i;
		for (int i=1;i<=a[n];++i)
			pre[i]=(pre[i]?pre[i]:pre[i-1]);
		for (int i=a[n];i>=1;--i)
			suc[i]=(suc[i]?suc[i]:suc[i+1]);
		for (int i=1;i<=m;++i)
			scanf("%d%d",&o[i].v,&o[i].w);
		memset(v,127,sizeof(ll)*(a[n]+1));
		v[0]=0;
		for (int i=1;i<=m;++i)
			for (int j=o[i].w;j<=a[n];++j)
				v[j]=min(v[j],v[j-o[i].w]+o[i].v);
		memset(g,255,sizeof(ll)*(a[n]+1));
		memset(f,255,sizeof(ll)*(a[n]+1));
		for (int i=1;i<=a[1];++i)
			f[i]=g[i]=0;
		bool bz=1;
		for (int i=2;i<=n && bz;++i){
			s[i]=s[i-1]+getg(a[i]);
			if (g[a[i]]==0x7f7f7f7f7f7f7f7f)
				bz=0;
		}
		printf("%lld\n",bz==0?-1:s[n]);
	}
	return 0;
}











T4

首先是个博弈题:两个人在玩取石子,石子的总量为 m m m,并且每个人取的石子数不能超过上一个人取的石子数。 f ( m ) f(m) f(m)为先手取最少多少是能保证必胜。
∑ i = 1 n ∑ m ∣ i f ( m ) \sum_{i=1}^n\sum_{m|i}f(m) i=1nmif(m)

这道题比赛的时候根本就没有思考过……

首先 f ( m ) f(m) f(m)是有通项的,可以通过打表或通过下述推理发现:
如果 m m m为奇数,那先手选 1 1 1
如果 m m m为偶数,那在接下来的过程中,谁选了奇数谁就倒霉,所以都会选偶数。于是就将两个石子合二为一,就相当于 f ( m / 2 ) f(m/2) f(m/2)
于是 f ( m ) = l o w b i t ( m ) f(m)=lowbit(m) f(m)=lowbit(m)
上面那个式子换一下就是 ∑ i = 1 n l o w b i t ( i ) ⌊ n i ⌋ \sum_{i=1}^nlowbit(i)\lfloor\frac{n}{i}\rfloor i=1nlowbit(i)in
考虑将 l o w b i t ( i ) lowbit(i) lowbit(i)相等的分开计算。令 g ( n ) = ∑ i = 1 n ⌊ n i ⌋ g(n)=\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor g(n)=i=1nin
g ( n ) g(n) g(n) l o w b i t ( i ) ≥ 1 lowbit(i)\geq 1 lowbit(i)1的个数, g ( ⌊ n 2 ⌋ ) g(\lfloor\frac{n}{2}\rfloor) g(2n) l o w b i t ( i ) ≥ 2 lowbit(i)\geq 2 lowbit(i)2的个数,依次类推。
答案就是 g ( n ) + ( 2 − 1 ) g ( ⌊ n 2 ⌋ ) + ( 4 − 2 ) g ( ⌊ n 4 ⌋ ) + . . . g(n)+(2-1)g(\lfloor\frac{n}{2}\rfloor)+(4-2)g(\lfloor\frac{n}{4}\rfloor)+... g(n)+(21)g(2n)+(42)g(4n)+...
计算 g ( n ) g(n) g(n)的时间是 n \sqrt n n ,上面那条式子用等比数列求和的方法分析出来时间是 n \sqrt n n

直接整除分块常数很大,卡不过。于是gmh大爷就发明了一种常数极小的方法:
x y = n xy=n xy=n的图像画出来,可以发现要求的是坐标轴与图图像之间夹的整点数量。
这个东西是关于 y = x y=x y=x对称的。
所以只需要前 n \sqrt n n 一个一个算,扩大两倍之后减去重复部分(即 ⌊ n ⌋ 2 \lfloor\sqrt n\rfloor^2 n 2

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
#define mo 998244353
ll n;
inline ll g(ll n){
	ll sq=sqrt(n);
	ll res=0;
	for (ll i=1;i<=sq;++i)
		res+=n/i;
	return (2*res%mo-sq*sq%mo+mo)%mo;
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%lld",&n);
	ll ans=g(n);
	for (ll k=1;1ll<<k<=n;++k)
		ans+=(1ll<<k-1)%mo*g(n>>k)%mo;
	ans%=mo;
	printf("%lld\n",ans);
	return 0;
}

T5

给出一个成直线排布的山脉,每个位置的海拔高度是随时间单调递减的函数。
若干个询问 [ t , l , r ] [t,l,r] [t,l,r],表示 t t t时刻, [ l , r ] [l,r] [l,r]区间的山脉可以储多少水(可以看作不在这个区间内的山脉铲平)。

答案等于上轮廓减下轮廓,下轮廓就是区间和。
上轮廓就是找出最高点之后,左边到最高点的前缀最大值和,右边到最高点的前缀最大值和。以下只说左边,右边同理:
线段树上,对于每个节点所代表的区间动态地维护前缀最大值。
询问的时候将 [ l , r ] [l,r] [l,r]对应的 l o g log log个区间找出来,很好算。
问题是怎么维护。

首先,对于一段长度为 L L L的区间,前缀最大值的修改次数是 O ( L ) O(L) O(L)的。
因为都是一次函数,某个数的前缀最大值可能在某个时候变成自己,然后在后面的某个时候又变回别人,从此它不可能成为最大值。每个一次函数顶多成为一次最大值,所以修改次数为 O ( L ) O(L) O(L)
试着预处理一下某个点大于左边的数的时间区间。
处理某个节点所代表的区间的时候,左半部分可以通过左儿子继承过来,
右半部分可以计算它完全大于左儿子所有数的区间(左儿子建出最大值的分段函数),然后和右儿子的信息取并。
这样时间复杂度是 O ( n lg ⁡ 2 n ) O(n \lg^2n) O(nlg2n)的。

接下来的问题是如何维护前缀最大值(支持区间求和)
考虑将某个数变成最大值的时候,它会覆盖原先它的前缀最大值所覆盖的区间。
将某个数不再出最大值时,它原先覆盖的区间被上一个位置的前缀最大值所覆盖。
修改形如:将某段区间全部赋值为某个数。
这个修改貌似可以在前面的预处理中一并处理出来。
这个东西可以套个线段树维护。每个数只需要搞一次,搞一次的时间复杂度是 O ( lg ⁡ n ) O(\lg n) O(lgn),一个数会出现在 O ( lg ⁡ n ) O(\lg n) O(lgn)个区间中,所以总时间是 O ( n lg ⁡ 2 n ) O(n\lg^2 n) O(nlg2n)
PS:好像可以用树状数组?

最终总时间就是 O ( n lg ⁡ 2 n ) O(n \lg^2 n) O(nlg2n)
我看std居然有5k,有点吓人。
表示还没有打,看看以后有没有机会吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "郭学军,王润秋。基于MPU6050和HMC5883的九轴传感器地磁场测量系统研究"是一篇关于使用九轴传感器进行地磁场测量的研究文章。该研究旨在通过结合MPU6050和HMC5883两种传感器,设计一种能够准确测量地磁场的系统。文章以化工自为刊物,突出了地磁场在化工领域中的重要性和应用价值。 研究背景介绍了地磁场的定义和特性,并指出了地磁场在化工工程中的多个应用领域,如地下管道的检测、石油勘探等。随后,文章详细介绍了MPU6050和HMC5883这两种九轴传感器的原理和特点,以及它们分别用于加速度和角速度测量、地磁场测量的方法。 接下来,文章详细描述了基于MPU6050和HMC5883的九轴传感器地磁场测量系统的设计和实现。系统采用了微处理器作为控制核心,通过对传感器输出号的处理和转换,实现了对地磁场的测量。其中,通过校准和滤波等技术手段,提高了测量的准确性和稳定性。 研究结果部分展示了实验数据和分析结果。通过对比系统测量值与标准值的差异,验证了系统的可靠性和准确性。实验结果表明,该系统能够精确地测量地磁场的强度和方向,并在化工领域中具有广泛的应用前景。 最后,文章总结了研究的成果和不足之处,并对未来的研究方向提出了展望。研究者指出,进一步优化和改进传感器的设计,提高系统的测量精度和稳定性,以及应用于更广泛的化工领域,都是未来研究的重点和挑战。 总的来说,这篇文章详细介绍了基于MPU6050和HMC5883九轴传感器的地磁场测量系统的研究。该系统具有准确测量地磁场的能力,对化工领域具有重要的应用价值和发展潜力。该研究为相关领域的学者和工程师提供了有价值的参考和借鉴。 ### 回答2: 《基于mpu6050和hmc5883的九轴传感器地磁场测量系统研究》是由郭学军和王润秋共同完成的研究项目。该研究旨在利用mpu6050和hmc5883两种传感器实现对地磁场的测量。 地磁场是地球所产生的磁场,它对于导航、定位和姿态控制等领域具有重要的应用价值。为了实现对地磁场的准确测量,研究团队选择了mpu6050和hmc5883这两种传感器。 mpu6050是一种六轴传感器,可以实时测量物体的加速度和角速度。而hmc5883是一种三轴磁强计,主要用于测量地磁场的强度和方向。通过将两种传感器进行组合,可以完整地获取九轴息,从而实现对地磁场的测量。 研究团队首先对mpu6050和hmc5883进行了校准和性能评估,确保传感器的准确度和稳定性。随后,他们开发了基于九轴传感器的地磁场测量系统,并进行了实验验证。 实验结果表明,该系统能够准确地测量地磁场的强度和方向。同时,由于mpu6050和hmc5883两种传感器具有体积小、功耗低等优点,该系统在应用于导航、定位和姿态控制等领域时具有较大的实用性和便利性。 综上所述,郭学军和王润秋基于mpu6050和hmc5883的九轴传感器地磁场测量系统研究为地磁场测量领域提供了一种新的解决方案。该系统准确度高、稳定性好,并具有实用性和便利性,有望在相关领域得到广泛应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值