ARC082简要题解

《 光 速 下 班 》
在这里插入图片描述
果然睡饱了打VP有奇妙加成吗

C题:
开个桶,统计一下相邻三个数的和,取个max。

#include<bits/stdc++.h>
using namespace std;
int ton[100010];
int n, ans;
int main() { 
	scanf("%d", &n);
	int val;
	for(int i=1;i<=n;++i) { 
		scanf("%d", &val);
		ton[val]++;
	} 
	for(int i=0;i<=100000;++i) 
		ans = max(ans, ton[i] + ton[i+1] + ton[i+2]);
	cout<<ans;
	return 0;
} 

D题:
发觉如果相邻k个元素都很不巧的命中了自己不该去的那个位置,那么我们花 ⌊ k + 1 2 ⌋ \lfloor {\frac{k+1}{2}}\rfloor 2k+1次操作,一定能给这串东西换成错排的。
别问我为啥加一然后下取整而不用上取整,没找到那符号
证明很显然,懒得证了。然后for一下,判一判,没了。

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int n, ans, cnt;
int main() { 
	scanf("%d", &n);
	for(int i=1;i<=n;++i) { 
		scanf("%d", &a[i]);
		if(a[i] == i) 
			cnt++;
		else { 
			ans += (cnt + 1) / 2;
			cnt = 0;
		} 
	}
	ans += (cnt + 1) / 2;
	cnt = 0;
	cout<<ans;
	return 0;
} 

E题:
看到算几就先跑路去做F的屑竟是我自己
拿到题之后懵住了www。
感觉那个贡献长得非常的奇怪,冷静了一下看出来了,对于一个凸多边形,他产生的贡献好像是“从他里面选择0个或者多个点的方案数”。
当时就感觉这个贡献很迷,不是人做的,于是转了一步,变成“恰好以这个凸多边形为凸包的点集数量。”
于是枚举凸多边形,算上面那玩意,就等价于了,有凸多边形的点集数量。
于是反过来搞,变成所有点集-全共线点集。
于是 O ( n 3 ) O(n^3) O(n3)枚举一下,对于有 c n t cnt cnt个点共线的情况,他会被统计 C c n t 2 C^{2}_{cnt} Ccnt2次,除下去就完事。

#include<bits/stdc++.h>
using namespace std;
long long pw[210];
const int mod = 998244353;
long long ans = 0;
struct node { 
	int x, y;
	node operator + (const node &a) const { 
		return {x + a.x, y + a.y};
	} 
	node operator - (const node &a) const { 
		return {x - a.x, y - a.y};
	} 
};
node sth[10010];
int n;

bool gx(node p1, node p2, node p3) { 
	node l1 = p2 - p1;
	node l2 = p3 - p2;
	return l1.x * l2.y == l2.x * l1.y;
} 

long long fpow(long long di, long long top) { 
	long long ret = 1;
	while(top) { 
		if(top % 2) 
			ret = ret * di % mod;
		di = di * di % mod;
		top /= 2;
	} 
	return ret;
} 

long long inv(int k) { 
	return fpow(k, mod-2);
} 

int main() { 
	pw[0] = 1;
	for(int i=1;i<=200;++i) 
		pw[i] = 2 * pw[i-1] % mod;
	scanf("%d", &n);
	for(int i=1;i<=n;++i) 
		scanf("%d%d", &sth[i].x, &sth[i].y);
	for(int i=1;i<=n;++i) { 
		for(int j=i+1;j<=n;++j) { 
			int cnt = 2;
			for(int k=1;k<=n;++k) { 
				if(k == i || k == j) 
					continue;
				cnt += gx(sth[i], sth[j], sth[k]);
			} 
			long long tim = pw[cnt] - 1 - cnt;
			tim %= mod, tim += mod, tim %= mod;
			long long xis = cnt * (cnt - 1) / 2;
			tim = tim * inv(xis) % mod;
			ans += tim;
			ans %= mod;
		} 
	} 
	long long tot = pw[n] - 1 - n;
	tot -= ans;
	tot %= mod, tot += mod, tot %= mod;
	cout<<tot;
	return 0;
} 

F题:
这玩意居然是个F题我的妈(
很容易想到,一顿翻转之后,这东西大概长这样子:在这里插入图片描述
其中横轴是 0 0 0时刻的 A A A中沙子数,纵轴是这么久之后的 A A A中沙子数,而中间这个显然是个一次的玩意,且斜率还是1。
然后就维护个左边的,拿来chkmax的下界,维护个右边的,拿来chkmin的上界。
按时间顺序遍历所有的flip和询问,维护到当前的 Δ \Delta Δ和chkmax、chkmin,拿到询问的时候根据当前信息回答一下。
注意如果这俩边界如果满足 [ c h k m a x , c h k m i n ] = ∅ [chkmax,chkmin]=\empty [chkmax,chkmin]=,那么说明之后的状态与初始值无关,特判一下就好了。
这东西调好了CE之后就直接过了你敢信。
下面那坨注释的赛中思考的时候写的。

#include<bits/stdc++.h>
using namespace std;
int X, n, m;
int r[100010];
struct quer { 
	int tim, val;
	bool operator < (const quer &a) const { 
		return tim < a.tim;
	} 
};
quer q[100010];
long long cmin, cmax, det;
int main() { 
	scanf("%d", &X);
	scanf("%d", &n);
	for(int i=1;i<=n;++i) { 
		scanf("%d", &r[i]);
	} 
	r[++n] = 1500000000;
	scanf("%d", &m);
	for(int i=1;i<=m;++i) 
		scanf("%d%d", &q[i].tim, &q[i].val);
	sort(q+1, q+m+1);
	cmin = X;
	cmax = 0;
	det = 0;
	int type = 0;
	//0则是A减,1则是A加。
	bool sp = 0;
	long long spval = 0;
	int nq = 1;
	for(int i=1;i<=n;++i) { 
		while(nq <= m && q[nq].tim <= r[i]) { 
			long long val = q[nq].val;
			int ntim = q[nq].tim;
			val = min(val, cmin);
			val = max(val, cmax);
			val += det;
			long long ndet = 0;
			if(type == 0) 
				ndet = -(ntim - r[i-1]);
			else
				ndet = ntim - r[i-1];
			if(sp) { 
				val = spval;
				val += ndet;
			} 
			else 
				val += ndet;
			val = min(val, 1ll * X);
			val = max(val, 1ll * 0);
			printf("%lld\n", val);
			nq++;
		} 
		int pre = r[i-1];
		int len = r[i] - r[i-1];
		if(type == 0) 
			det = det - len, spval = spval - len;
		else
			det = det + len, spval = spval + len;
		spval = min(spval, 1ll * X), spval = max(spval, 1ll * 0);
		if(det < 0) { 
			cmax = max(cmax, -det);
			if(cmax > cmin) 
				sp = 1;
		} 
		if(det > 0) { 
			cmin = min(cmin, X - det);
			if(cmax > cmin)
				sp = 1;
		} 
		type ^= 1;
	} 
	return 0;
} 
/*
考虑一个操作。
比如A在上面持续了15s,那么,对于初始A为[0, 15]的所有东西,我们看做他初始变成了15
对于15以上的东西,我们维护一个叫det的变量,即,这玩意的A部分被减去了det。
emm好像可以维护两个变量,一个叫cmin,一个叫cmax,然后拿到一个query,先对这两个东西进行checkmin和checkmax。
再维护一个叫det的东西,表示,A的初始值如果落在[cmax, cmin]以内,那么他会经历怎么样一个delta值。
好像就没事了?
推一下,假设当前cmin = 0, cmax = X。
记录一个det,记录一个type。
一次flip,则type ^= 1
然后该加加,该减减,出负数了/大于X了,就修改Cmin和Cmax。


*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值