A. Game
题意:
n
个
只
包
含
0
和
1
的
数
组
,
你
一
开
始
在
a
[
1
]
位
置
,
求
走
到
a
[
n
]
位
置
的
最
小
代
价
n个只包含0和1的数组,你一开始在a[1]位置,求走到a[n]位置的最小代价
n个只包含0和1的数组,你一开始在a[1]位置,求走到a[n]位置的最小代价
如
果
a
[
i
]
=
a
[
i
+
1
]
=
1
,
你
可
以
从
i
走
到
i
+
1
,
代
价
为
0
如果a[i]=a[i+1]=1,你可以从i走到i+1,代价为0
如果a[i]=a[i+1]=1,你可以从i走到i+1,代价为0
如
果
a
[
i
]
=
a
[
j
]
=
1
[
i
<
j
]
,
你
可
以
从
i
走
到
j
,
代
价
为
j
−
i
,
只
能
走
一
次
如果a[i]=a[j]=1[i<j],你可以从i走到j,代价为j-i,只能走一次
如果a[i]=a[j]=1[i<j],你可以从i走到j,代价为j−i,只能走一次
思路:
因
为
第
二
种
走
法
只
能
走
一
次
因为第二种走法只能走一次
因为第二种走法只能走一次
所
以
找
到
第
一
个
连
续
的
一
的
最
后
一
个
位
置
L
所以找到第一个连续的一的最后一个位置L
所以找到第一个连续的一的最后一个位置L
和
最
后
一
个
连
续
的
一
的
第
一
个
位
置
R
和最后一个连续的一的第一个位置R
和最后一个连续的一的第一个位置R
答
案
即
为
R
−
L
答案即为R-L
答案即为R−L
时间复杂度:
O
n
On
On
int n ;
int a[N] ;
signed main()
{
cf
{
cin >> n ;
fer(i,1,n) sf(a[i]) ;
int l = -1 , r = -1 ;
fer(i,1,n)
{
if(!a[i])
{
l = i - 1 ;
break ;
}
}
der(i,n,1)
{
if(!a[i])
{
r = i + 1 ;
break ;
}
}
de(r - l) ;
}
return 0 ;
}
B. Game of Ball Passing
题意:
给
你
一
个
n
个
数
的
数
组
,
a
[
i
]
表
示
i
这
个
人
传
了
a
[
i
]
次
球
给你一个n个数的数组,a[i]表示i这个人传了a[i]次球
给你一个n个数的数组,a[i]表示i这个人传了a[i]次球
现
在
问
你
进
行
了
最
少
多
少
次
传
球
使
得
所
有
人
都
可
以
传
完
现在问你进行了最少多少次传球使得所有人都可以传完
现在问你进行了最少多少次传球使得所有人都可以传完
每
次
传
球
从
任
意
一
个
人
开
始
,
只
要
传
给
除
他
之
外
的
人
即
可
每次传球从任意一个人开始,只要传给除他之外的人即可
每次传球从任意一个人开始,只要传给除他之外的人即可
思路:
把
每
次
传
球
转
化
一
下
把每次传球转化一下
把每次传球转化一下
等
价
于
首
先
选
一
个
i
,
使
a
[
i
]
−
1
等价于首先选一个i,使a[i]-1
等价于首先选一个i,使a[i]−1
然
后
在
任
意
选
2
个
不
同
的
下
标
i
,
j
,
使
a
[
i
]
−
1
,
a
[
j
]
−
1
,
可
以
进
行
无
数
次
然后在任意选2个不同的下标i,j,使a[i]-1,a[j]-1,可以进行无数次
然后在任意选2个不同的下标i,j,使a[i]−1,a[j]−1,可以进行无数次
不
考
虑
首
先
选
一
个
i
,
使
a
[
i
]
−
1
的
情
况
下
不考虑首先选一个i,使a[i]-1的情况下
不考虑首先选一个i,使a[i]−1的情况下
记
录
一
下
数
组
总
和
s
u
m
和
数
组
最
大
值
m
a
x
v
记录一下数组总和sum和数组最大值maxv
记录一下数组总和sum和数组最大值maxv
如
果
s
u
m
−
m
a
x
v
>
=
m
a
x
v
如果sum-maxv>=maxv
如果sum−maxv>=maxv
说
明
一
次
传
球
即
可
说明一次传球即可
说明一次传球即可
考
虑
首
先
选
一
个
i
,
使
a
[
i
]
−
1
的
情
况
下
考虑首先选一个i,使a[i]-1的情况下
考虑首先选一个i,使a[i]−1的情况下
那
我
们
二
分
进
行
了
多
少
次
传
球
m
i
d
那我们二分进行了多少次传球mid
那我们二分进行了多少次传球mid
如
果
m
i
d
次
可
以
传
球
成
功
,
说
明
m
i
d
可
以
变
小
如果mid次可以传球成功,说明mid可以变小
如果mid次可以传球成功,说明mid可以变小
否
则
m
i
d
变
大
否则mid变大
否则mid变大
m
i
d
次
传
球
,
等
价
于
你
可
以
先
进
行
m
i
d
次
选
一
个
i
,
使
a
[
i
]
−
1
mid次传球,等价于你可以先进行mid次选一个i,使a[i]-1
mid次传球,等价于你可以先进行mid次选一个i,使a[i]−1
然
后
在
任
意
选
2
个
不
同
的
下
标
i
,
j
,
使
a
[
i
]
−
1
,
a
[
j
]
−
1
,
可
以
进
行
无
数
次
然后在任意选2个不同的下标i,j,使a[i]-1,a[j]-1,可以进行无数次
然后在任意选2个不同的下标i,j,使a[i]−1,a[j]−1,可以进行无数次
即 s u m − m a x v > = m a x v − m i d 即 可 即sum-maxv>=maxv-mid即可 即sum−maxv>=maxv−mid即可
时间复杂度: O n On On
int n ;
int a[N] ;
int s , v ;
int get(int mid)
{
if(s - v >= v - mid) return 1 ;
return 0 ;
}
signed main()
{
cf
{
cin >> n ;
fer(i,1,n) sf(a[i]) ;
s = 0 , v = 0 ;
fer(i,1,n) s += a[i] , v = max(v , a[i]) ;
if(!v)
{
puts("0") ;
continue ;
}
int l = 1 , r = 1e10 ;
while(l < r)
{
int mid = l + r >> 1 ;
if(get(mid)) r = mid ;
else l = mid + 1 ;
}
de(l) ;
}
return 0 ;
}
C. Weird Sum
题意:
给
你
一
个
n
∗
m
的
方
格
,
每
个
方
格
c
[
i
]
[
j
]
都
有
一
个
颜
色
k
,
求
给你一个n*m的方格,每个方格c[i][j]都有一个颜色k,求
给你一个n∗m的方格,每个方格c[i][j]都有一个颜色k,求
∑
k
=
1
1
e
5
∑
x
1
=
1
n
∑
y
1
=
1
m
∑
x
2
=
i
+
1
n
∑
y
2
=
j
+
1
m
(
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
)
∗
[
c
[
x
1
]
[
y
1
]
=
k
且
c
[
x
2
]
[
y
2
]
=
k
]
\sum_{k=1}^{1e5}{\sum_{x1=1}^{n}\sum_{y1=1}^{m}\sum_{x2=i+1}^{n}\sum_{y2=j+1}^{m}{(|x1-x2|+|y1-y2|)}}*[ c[x1][y1]=k且c[x2][y2]=k ]
k=1∑1e5x1=1∑ny1=1∑mx2=i+1∑ny2=j+1∑m(∣x1−x2∣+∣y1−y2∣)∗[c[x1][y1]=k且c[x2][y2]=k]
思路:
首
先
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
可
以
分
开
算
首先|x1-x2|+|y1-y2|可以分开算
首先∣x1−x2∣+∣y1−y2∣可以分开算
所
以
我
们
可
以
预
处
理
所
有
颜
色
的
不
同
的
横
坐
标
和
纵
坐
标
所以我们可以预处理所有颜色的不同的横坐标和纵坐标
所以我们可以预处理所有颜色的不同的横坐标和纵坐标
现
在
问
题
等
价
于
对
于
任
意
一
个
序
列
现在问题等价于对于任意一个序列
现在问题等价于对于任意一个序列
a
1
a_1
a1
a
2
a_2
a2 …
a
n
a_n
an
求
所
有
不
同
颜
色
的
∑
i
=
1
n
∑
j
=
i
+
1
n
∣
a
[
i
]
−
a
[
j
]
∣
求所有不同颜色的\sum_{i=1}^{n}{\sum_{j=i+1}^{n}|a[i]-a[j]|}
求所有不同颜色的∑i=1n∑j=i+1n∣a[i]−a[j]∣
首
先
将
数
组
排
序
之
后
首先将数组排序之后
首先将数组排序之后
因
为
∑
i
=
1
n
∑
j
=
i
+
1
n
∣
a
[
i
]
−
a
[
j
]
∣
=
∑
i
=
1
n
∑
j
=
1
i
−
1
∣
a
[
i
]
−
a
[
j
]
∣
因为\sum_{i=1}^{n}{\sum_{j=i+1}^{n}|a[i]-a[j]|}=\sum_{i=1}^{n}{\sum_{j=1}^{i-1}|a[i]-a[j]|}
因为∑i=1n∑j=i+1n∣a[i]−a[j]∣=∑i=1n∑j=1i−1∣a[i]−a[j]∣
所
以
记
录
前
缀
和
直
接
加
即
可
所以记录前缀和直接加即可
所以记录前缀和直接加即可
时间复杂度: O n m l o g n m Onmlognm Onmlognm
int n , m ;
vector<int> g[N] ;
int res ;
void solve(vector<int> &v)
{
sort(all(v)) ;
int s = 0 ;
for(int i = 0 ; i < sz(v) ; i ++)
{
res += v[i] * i - s ;
s += v[i] ;
}
}
signed main()
{
cin >> n >> m ;
vector<vector<int>> a(n + 1 , vector<int>(m + 1 , 0)) ;
fer(i,1,n)
fer(j,1,m)
{
sf(a[i][j]) ;
g[a[i][j] * 2].pb(i) ;
g[a[i][j] * 2 + 1].pb(j) ;
}
fer(i,1,2e5 + 10)
{
if(g[i].size())
solve(g[i]) ;
}
de(res) ;
return 0 ;
}
D. Integral Array
题意:
给
你
一
个
n
个
数
的
数
组
,
如
果
数
组
中
没
有
出
现
a
[
j
]
/
a
[
i
]
,
[
a
[
j
]
>
=
a
[
i
]
,
1
<
=
i
,
j
<
=
n
]
给你一个n个数的数组,如果数组中没有出现a[j]/a[i],[a[j]>=a[i],1<=i,j<=n]
给你一个n个数的数组,如果数组中没有出现a[j]/a[i],[a[j]>=a[i],1<=i,j<=n]
输
出
N
o
输出No
输出No
否
则
输
出
Y
e
s
否则输出Yes
否则输出Yes
思路:
对
于
数
组
中
的
每
个
数
,
我
们
可
以
枚
举
它
的
倍
数
对于数组中的每个数,我们可以枚举它的倍数
对于数组中的每个数,我们可以枚举它的倍数
假
设
对
于
i
这
个
数
,
它
的
倍
数
为
j
假设对于i这个数,它的倍数为j
假设对于i这个数,它的倍数为j
那
么
区
间
[
i
∗
j
,
i
∗
j
+
i
−
1
]
中
的
任
何
一
个
数
x
/
i
=
j
那么区间[i*j,i*j+i-1]中的任何一个数x/i=j
那么区间[i∗j,i∗j+i−1]中的任何一个数x/i=j
所
以
如
果
i
这
个
数
和
x
这
个
数
都
同
时
出
现
过
的
话
,
那
么
j
也
必
须
出
现
所以如果i这个数和x这个数都同时出现过的话,那么j也必须出现
所以如果i这个数和x这个数都同时出现过的话,那么j也必须出现
如
果
j
没
有
出
现
过
的
话
,
直
接
输
出
N
o
即
可
如果j没有出现过的话,直接输出No即可
如果j没有出现过的话,直接输出No即可
时间复杂度: 时 间 复 杂 度 : n / 1 + n / 2 + . . . . . + n / n ≈ n l o g n 时间复杂度:n/1+n/2+.....+n/n \approx nlogn 时间复杂度:n/1+n/2+.....+n/n≈nlogn
int n , m ;
int a[N] ;
int cnt[N] ;
int tt[N] ;
int cc[N] ;
signed main()
{
cf
{
cin >> n >> m ;
fer(i,0,m * 2 + 10) cnt[i] = 0 , cc[i] = 0 ;
fer(i,1,n) scanf("%d",&a[i]) , cnt[a[i]] = 1 , cc[a[i]] = 1;
fer(i,1,m * 2 + 10) cnt[i] += cnt[i - 1] ;
int f1 = 0 ;
for(int i = 1 ; i <= m ; i ++)
{ if(cc[i])
for(int j = 1 ; j * i <= m ; j ++)
{
int l = j * i , r = j * i + i - 1 ;
if(cnt[r] - cnt[l - 1])
{
if(!cc[j]) f1 = 1 ;
}
}
}
if(f1) puts("No") ;
else puts("Yes") ;
}
return 0 ;
}