Anti Light’s Cell Guessing 有
n
×
m
n\times m
n×m 的格子,其中一个位置有雷,但是不知道在哪里。 你需要选
k
k
k 个格子,电脑会返回这
k
k
k 个格子与雷的曼哈顿距离。 求最小的
k
k
k,不管雷在哪里,你都能判断出。
样例组数
T
≤
1
0
4
T \le 10^4
T≤104
1
≤
n
,
m
≤
1
0
9
1\le n,m\le 10^9
1≤n,m≤109
思路
显然成立的条件:
n
=
m
=
1
n=m=1
n=m=1,不用选了,
k
=
0
k=0
k=0 如果
min
(
n
,
m
)
=
1
\min(n,m)=1
min(n,m)=1,那么你选一个最边上的格子,就能判断出雷在哪了 否则,你最少需要选两个格子,比如
(
1
,
1
)
(1,1)
(1,1) 和
(
1
,
m
)
(1,m)
(1,m) 对于相同距离这个角落的格子的曼哈顿距离,雷一定在那条斜的对角线上。 一个斜率
k
=
1
k=1
k=1 的对角线与斜率
k
=
−
1
k=-1
k=−1 的对角线的交点,就能唯一确定那个雷。
代码
时间复杂度:
O
(
T
)
O(T)
O(T)
#include<bits/stdc++.h>
using namespace std;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}typedeflonglong ll;constint MAX =2e5+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;intmain(){int T;scanf("%d",&T);while(T--){int n,m;scanf("%d%d",&n,&m);if(n ==1&& m ==1){puts("0");}elseif(min(n,m)==1){puts("1");}else{puts("2");}}return0;}
B:Kalindrome Array
题意
Kalindrome Array 给定一个长度为
n
n
n 的序列
a
n
a_n
an 问你是否能选择一个
x
x
x,删除这个序列里面部分等于
x
x
x 的元素(也可以不删除),使得序列成为一个回文序列?
1
≤
a
i
≤
n
≤
2
⋅
1
0
5
1\le a_i\le n\le 2\cdot10^5
1≤ai≤n≤2⋅105
思路
很妙的题。 首先我们发现,如果选择了
x
x
x 可以让这个序列删成回文的,那么我不妨把所有的
x
x
x 都删除了,是等价的。
但是,我不能把每种元素都试一遍,复杂度是
n
2
n^2
n2 了,我是不是只用判断几次就可以了呢? 考虑到,如果我们考虑
a
n
a_n
an,每次查看头和尾是否相同。如果相同,则无所谓了。 如果不同,那么
a
l
a_l
al 和
a
r
a_r
ar 我都可以尝试删除一下,看看是否能成为回文。如果都不行,自然就不行了。
代码
时间复杂度:
O
(
n
)
O(n)
O(n)
#include<bits/stdc++.h>
using namespace std;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}typedeflonglong ll;constint MAX =2e5+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;int aa[MAX];int bb[MAX];intmain(){int T;scanf("%d",&T);while(T--){int n;scanf("%d",&n);for(int i =1;i <= n;++i)scanf("%d",&aa[i]);int st =1,ed = n;int may1 =0,may2 =0;for(st =1;st <= n /2;++st,--ed){if(aa[st]!= aa[ed]){
may1 = aa[st];
may2 = aa[ed];break;}}if(!may1){puts("YES");continue;}int cnt =0;for(int i =1;i <= n;++i){if(aa[i]!= may1){
bb[++cnt]= aa[i];}}
bool can = true;for(int i =1;i <= cnt /2;++i){if(bb[i]!= bb[cnt - i +1]){
can = false;break;}}if(can){puts("YES");continue;}
cnt =0;for(int i =1;i <= n;++i){if(aa[i]!= may2){
bb[++cnt]= aa[i];}}
can = true;for(int i =1;i <= cnt /2;++i){if(bb[i]!= bb[cnt - i +1]){
can = false;break;}}if(can){puts("YES");continue;}puts("NO");}return0;}
C:Keshi Is Throwing a Party
题意
有
n
n
n 个人,从左往右排成一排,你要选出一些人来。 第
i
i
i 个人能被选择,满足他左边最多被选有
b
i
b_i
bi 个人,他右边最多被选
a
i
a_i
ai 个人 问你,你最多能选出几个人?
1
≤
n
≤
2
⋅
1
0
5
1\le n\le 2\cdot 10^5
1≤n≤2⋅105
思路
又是很妙的题… 想了很久的
d
p
dp
dp ,怎么想都只能做成
n
2
n^2
n2 的。 但是突然想到了二分,然后思路直接出来了。 人数符合二分的性质,二分可以的人数,这样你就知道
a
i
a_i
ai 的合法性判定了,他右边被选多少人是确定的。 但是
b
i
b_i
bi 呢?其实只要贪心,能选就行,因为选完这个人之后,他左边不会再加人了。
代码
时间复杂度:
O
(
n
log
n
)
O(n\log n)
O(nlogn)
#include<bits/stdc++.h>
using namespace std;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}typedeflonglong ll;constint MAX =2e5+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;int aa[MAX],bb[MAX];
bool check(int n,int ren){int zuo =0;int you = ren -1;for(int i =1;i <= n;++i){if(bb[i]>= zuo && aa[i]>= you){
ren--;
zuo++;
you--;if(ren ==0)return true;}}return false;}intmain(){int T;scanf("%d",&T);while(T--){int n;scanf("%d",&n);for(int i =1;i <= n;++i){scanf("%d%d",&aa[i],&bb[i]);}int L =1,R = n;while(L < R){int M =(L + R +1)>>1;if(check(n,M))L = M;else R = M -1;}printf("%d\n",L);}return0;}
D:Not Quite Lee
题意
Not Quite Lee 序列
b
[
1
,
2
,
⋯
,
m
]
b[1,2,\cdots,m]
b[1,2,⋯,m] 是好的,如果存在
s
u
m
i
sum_i
sumi 等于连续的某
b
i
b_i
bi 个数字的和,且
∑
s
u
m
i
=
0
\sum sum_i=0
∑sumi=0 给定一个序列
a
n
a_n
an,问你有多少个非空子序列是好的。
2
≤
n
≤
2
⋅
1
0
5
2\le n\le 2\cdot 10^5
2≤n≤2⋅105
1
≤
a
i
≤
1
0
9
1\le a_i\le 10^9
1≤ai≤109
我们把所有
a
i
a_i
ai,要求长度为
a
i
a_i
ai 的连续的数,我们先放
0
0
0,再放
1
,
−
1
,
2
,
−
2
,
3
,
⋯
1,-1,2,-2,3,\cdots
1,−1,2,−2,3,⋯ 这样,
a
i
a_i
ai 构成的
s
u
m
i
=
a
i
2
sum_i=\frac{a_i}{2}
sumi=2ai 这个序列每次可以整体向左或者向右移动一个单位,那么
s
u
m
i
=
a
i
2
+
k
i
a
i
sum_i=\frac{a_i}{2}+k_ia_i
sumi=2ai+kiai 如果满足
∑
s
u
m
i
=
0
\sum sum_i=0
∑sumi=0,容易想到必须满足
gcd
(
a
1
,
⋯
,
a
m
)
=
g
,
满
足
g
∣
∑
a
i
2
\gcd(a_1,\cdots,a_m)=g,满足 g\Big| \frac{\sum a_i}{2}
gcd(a1,⋯,am)=g,满足g∣∣∣2∑ai 这样,式子复杂度是
O
(
2
n
log
n
)
O(2^n\log n)
O(2nlogn) 啊,感觉做不了,赛场我到这里就嗝屁了…但是可以继续推的!
g
∣
∑
a
i
2
即
2
g
∣
∑
a
i
即
2
∣
∑
a
i
g
即
2
∣
∑
a
i
g
g\Big| \frac{\sum a_i}{2}\\\ \\ 即\ 2g\Big|\sum a_i\\\ \\ 即\ 2\Big|\frac{\sum a_i}{g}\\\ \\ 即\ 2\Big|\sum\frac{a_i}{g}
g∣∣∣2∑ai即2g∣∣∣∑ai即2∣∣∣g∑ai即2∣∣∣∑gai
可以发现,这里是否满足,取决于
a
i
g
\frac{a_i}{g}
gai 为奇数的个数 我们设
f
(
x
)
f(x)
f(x) 表示
x
x
x 有多少个因子
2
2
2 记
t
t
t 表示有多少个
a
i
a_i
ai 满足
f
(
a
i
)
=
m
n
=
min
{
f
(
a
1
)
,
⋯
,
f
(
a
m
)
}
f(a_i)=mn=\min\{f(a_1),\cdots,f(a_m)\}
f(ai)=mn=min{f(a1),⋯,f(am)} 我们发现,
f
(
x
)
=
m
n
f(x)=mn
f(x)=mn,那么
x
g
\frac{x}{g}
gx 是奇数;
f
(
x
)
>
m
n
f(x)>mn
f(x)>mn,那么
x
g
\frac{x}{g}
gx 是偶数
那么有多少个这样的子序列是不满足要求的呢? 即我们
t
t
t 中选择奇数个,这样不会让
2
∣
∑
a
i
g
2\Big|\sum\frac{a_i}{g}
2∣∣∣∑gai 满足 方案数很好算了。
t
t
t 个中选择奇数个的方案为
2
t
−
1
2^{t-1}
2t−1,剩下的
f
(
x
)
>
m
n
f(x)>mn
f(x)>mn 的所有个数记为
y
y
y,这里的都是可选可不选,方案为
2
y
2^y
2y,两个相乘即可.
我们枚举所有的
m
n
mn
mn 即可直接计算出所有不符合要求的序列。总数减去不符合的即可。
代码
时间复杂度:
O
(
n
log
n
)
O(n\log n)
O(nlogn)
#include<bits/stdc++.h>
using namespace std;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}typedeflonglong ll;constint MAX =2e5+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;
ll qpow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){a%=p;ll res =1LL;while(n){if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return0;}return res;}
ll inv(ll a){/* */returnqpow(a,MOD-2);}
ll inv(ll a,ll p){returnqpow(a,p-2,p);}int num[50];int pre[50];intmain(){int n;scanf("%d",&n);for(int i =1;i <= n;++i){int cnt =0;int t;scanf("%d",&t);while(t %2==0){
t /=2;
cnt++;}
num[cnt]++;}
pre[0]= num[0];for(int i =1;i <=40;++i){
pre[i]= pre[i-1]+ num[i];}
ll ans =(qpow(2,n)-1+ MOD)% MOD;for(int i =1;i <=35;++i){if(num[i])
ans =(ans -qpow(2,num[i]-1)*qpow(2,pre[40]- pre[i])% MOD + MOD)% MOD;}printf("%lld",ans);return0;}
E:AmShZ and G.O.A.T.
题意
AmShZ and G.O.A.T. 一个序列的平均值为
A
V
G
AVG
AVG,说这个序列是好的,当其中
>
A
V
G
>AVG
>AVG 的元素个数小于等于其中
<
A
V
G
<AVG
<AVG 的元素个数
给定一个序列
a
n
a_n
an,问你最少删除多少个元素,让剩下的序列的所有子序列都是好的。
2
≤
n
≤
2
⋅
1
0
5
2\le n\le 2\cdot 10^5
2≤n≤2⋅105
1
≤
a
i
≤
1
0
9
1\le a_i\le 10^9
1≤ai≤109
思路
从最简单的出发。假设有三个元素
a
<
b
<
c
a<b<c
a<b<c 当这个序列是好的,则
A
V
G
=
a
+
b
+
c
3
≥
b
AVG=\frac{a+b+c}{3}\ge b
AVG=3a+b+c≥b,即
c
≥
2
b
−
a
c\ge2b-a
c≥2b−a 有一个奇怪的结论(?)若一个序列中任意长度为
3
3
3 的子序列都是好的,那么这个序列也是好的。
我们只要算出最长好的序列即可。 假设我们算到一半,好的序列得到了一个
[
b
1
,
b
2
,
⋯
,
b
x
]
[b_1,b_2,\cdots,b_x]
[b1,b2,⋯,bx] 此时我们要求最优的,肯定是最小的
c
c
c,满足
c
≥
b
x
−
b
1
c\ge b_x-b_1
c≥bx−b1,因为右侧是理论最大值,必须要满足的
我们可以暴力枚举好的序列的开头,每次用二分算出下一个
c
c
c,注意到由于
c
≥
2
b
−
a
c\ge 2b-a
c≥2b−a,所以复杂度总体是
log
\log
log 级别的
代码
时间复杂度:
O
(
n
log
n
log
{
max
a
i
}
)
O(n\log n \log \{\max a_i\})
O(nlognlog{maxai})
#include<bits/stdc++.h>
using namespace std;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}typedeflonglong ll;constint MAX =2e5+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;
ll qpow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){a%=p;ll res =1LL;while(n){if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return0;}return res;}
ll inv(ll a){/* */returnqpow(a,MOD-2);}
ll inv(ll a,ll p){returnqpow(a,p-2,p);}int aa[MAX];intmain(){int T;scanf("%d",&T);while(T--){int n;scanf("%d",&n);for(int i =1;i <= n;++i)scanf("%d",&aa[i]);int ans =0;for(int i =1;i <= n;++i){if(aa[i]== aa[i-1])continue;int cnt =0,pos = i;while(pos <= n){
pos =lower_bound(aa + pos +1,aa + n +1,2* aa[pos]- aa[i])- aa;
cnt++;}
ans =max(ans,cnt);}printf("%d\n",n - ans);}return0;}
【解题报告】Codeforces Global Round 17A:Anti Light's Cell Guessing题意思路代码B:Kalindrome Array题意思路代码C:Keshi Is Throwing a Party题意思路代码D:Not Quite Lee题意思路代码E:AmShZ and G.O.A.T.题意思路代码【解题报告】Codeforces Global Round 17A:Anti Light’s Cell Guessing题意Anti Light’s Cell