《 光 速 下 班 》
果然睡饱了打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。
*/